1#![allow(non_snake_case)]
9
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::rc::Rc;
13
14use cranpose_core::hash::default;
15
16mod alignment;
17mod background;
18mod blur;
19mod chain;
20mod clickable;
21mod draw_cache;
22mod fill;
23mod focus;
24mod graphics_layer;
25mod local;
26mod offset;
27mod padding;
28pub(crate) mod pointer_input;
29mod rotary_input;
30mod scroll;
31mod semantics;
32mod shadow;
33mod size;
34mod slices;
35mod weight;
36
37pub use crate::draw::{DrawCacheBuilder, DrawCommand};
38#[allow(unused_imports)]
39pub use chain::{ModifierChainHandle, ModifierChainInspectorNode, ModifierLocalsHandle};
40pub use cranpose_foundation::{
41 modifier_element, AnyModifierElement, DynModifierElement, FocusState, PointerEvent,
42 PointerEventKind, PointerSource, RotaryScrollEvent, SemanticsConfiguration,
43};
44use cranpose_foundation::{ModifierNodeElement, NodeCapabilities};
45#[allow(unused_imports)]
46pub use cranpose_ui_graphics::{
47 BlendMode, BlurredEdgeTreatment, Brush, Color, ColorFilter, CompositingStrategy, CornerRadii,
48 CutDirection, Dp, DpOffset, EdgeInsets, GradientCutMaskSpec, GradientFadeMaskSpec,
49 GraphicsLayer, LayerShape, Point, Rect, RenderEffect, RoundedCornerShape, RuntimeShader,
50 Shadow, ShadowScope, Size, TransformOrigin,
51};
52use cranpose_ui_layout::{Alignment, HorizontalAlignment, IntrinsicSize, VerticalAlignment};
53#[allow(unused_imports)]
54pub use focus::{FocusDirection, FocusRequester};
55pub use graphics_layer::GlassMaterial;
56pub(crate) use local::{
57 ModifierLocalAncestorResolver, ModifierLocalSource, ModifierLocalToken, ResolvedModifierLocal,
58};
59#[allow(unused_imports)]
60pub use local::{ModifierLocalKey, ModifierLocalReadScope};
61#[allow(unused_imports)]
62pub use pointer_input::{AwaitPointerEventScope, PointerInputScope};
63pub use rotary_input::RotaryInputModifierNode;
64pub use semantics::{collect_semantics_from_chain, collect_semantics_from_modifier};
65pub use slices::{
66 collect_modifier_slices, collect_modifier_slices_into, collect_slices_from_modifier,
67 ModifierNodeSlices, ModifierNodeSlicesDebugStats,
68};
69#[cfg(feature = "test-helpers")]
71pub use scroll::{last_fling_velocity, reset_last_fling_velocity};
72
73use crate::modifier_nodes::ClipToBoundsElement;
74use focus::{FocusRequesterElement, FocusTargetElement};
75use local::{ModifierLocalConsumerElement, ModifierLocalProviderElement};
76use semantics::SemanticsElement;
77
78#[derive(Clone, Debug, Default)]
80pub struct InspectorInfo {
81 properties: Vec<InspectorProperty>,
82}
83
84impl InspectorInfo {
85 pub fn new() -> Self {
86 Self::default()
87 }
88
89 pub fn add_property<V: Into<String>>(&mut self, name: &'static str, value: V) {
90 self.properties.push(InspectorProperty {
91 name,
92 value: value.into(),
93 });
94 }
95
96 pub fn properties(&self) -> &[InspectorProperty] {
97 &self.properties
98 }
99
100 pub fn is_empty(&self) -> bool {
101 self.properties.is_empty()
102 }
103
104 pub fn add_dimension(&mut self, name: &'static str, constraint: DimensionConstraint) {
105 self.add_property(name, describe_dimension(constraint));
106 }
107
108 pub fn add_offset_components(
109 &mut self,
110 x_name: &'static str,
111 y_name: &'static str,
112 offset: Point,
113 ) {
114 self.add_property(x_name, offset.x.to_string());
115 self.add_property(y_name, offset.y.to_string());
116 }
117
118 pub fn add_alignment<A>(&mut self, name: &'static str, alignment: A)
119 where
120 A: fmt::Debug,
121 {
122 self.add_property(name, format!("{alignment:?}"));
123 }
124}
125
126#[derive(Clone, Debug, PartialEq)]
128pub struct InspectorProperty {
129 pub name: &'static str,
130 pub value: String,
131}
132
133#[derive(Clone, Debug, PartialEq)]
135pub struct ModifierInspectorRecord {
136 pub name: &'static str,
137 pub properties: Vec<InspectorProperty>,
138}
139
140#[derive(Clone, Debug)]
142pub(crate) struct InspectorMetadata {
143 name: &'static str,
144 info: InspectorInfo,
145}
146
147impl InspectorMetadata {
148 pub(crate) fn new<F>(name: &'static str, recorder: F) -> Self
149 where
150 F: FnOnce(&mut InspectorInfo),
151 {
152 let mut info = InspectorInfo::new();
153 recorder(&mut info);
154 Self { name, info }
155 }
156
157 fn is_empty(&self) -> bool {
158 self.info.is_empty()
159 }
160
161 fn to_record(&self) -> ModifierInspectorRecord {
162 ModifierInspectorRecord {
163 name: self.name,
164 properties: self.info.properties().to_vec(),
165 }
166 }
167}
168
169fn describe_dimension(constraint: DimensionConstraint) -> String {
170 match constraint {
171 DimensionConstraint::Unspecified => "unspecified".to_string(),
172 DimensionConstraint::Points(value) => value.to_string(),
173 DimensionConstraint::Fraction(value) => format!("fraction({value})"),
174 DimensionConstraint::Intrinsic(size) => format!("intrinsic({size:?})"),
175 }
176}
177
178pub(crate) fn inspector_metadata<F>(name: &'static str, recorder: F) -> InspectorMetadata
179where
180 F: FnOnce(&mut InspectorInfo),
181{
182 if !inspector_metadata_enabled() {
185 return InspectorMetadata::new(name, |_| {});
186 }
187 InspectorMetadata::new(name, recorder)
188}
189
190pub(crate) fn modifier_debug_enabled() -> bool {
191 #[cfg(not(target_arch = "wasm32"))]
192 {
193 cranpose_core::env_flag!("COMPOSE_DEBUG_MODIFIERS")
194 }
195 #[cfg(target_arch = "wasm32")]
196 {
197 false
198 }
199}
200
201fn inspector_metadata_enabled() -> bool {
202 cfg!(test) || modifier_debug_enabled()
203}
204
205#[derive(Clone)]
211enum ModifierKind {
212 Empty,
214 Single {
216 elements: Rc<Vec<DynModifierElement>>,
217 inspector: Rc<Vec<InspectorMetadata>>,
218 },
219}
220
221const FINGERPRINT_KIND_EMPTY: u8 = 0;
222const FINGERPRINT_KIND_SINGLE: u8 = 1;
223
224const FINGERPRINT_EMPTY_STRICT_SEED: u64 = 0x243f_6a88_85a3_08d3;
225const FINGERPRINT_EMPTY_STRUCTURAL_SEED: u64 = 0x1319_8a2e_0370_7344;
226const FINGERPRINT_SINGLE_STRICT_SEED: u64 = 0xa409_3822_299f_31d0;
227const FINGERPRINT_SINGLE_STRUCTURAL_SEED: u64 = 0x082e_fa98_ec4e_6c89;
228const FINGERPRINT_SEQUENCE_MUL: u64 = 0x9e37_79b1_85eb_ca87;
229const FINGERPRINT_STRICT_UPDATE_TAG: u64 = 0xdbe6_d5d5_fe4c_ce2f;
230const FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG: u64 = 0x94d0_49bb_1331_11eb;
231
232#[derive(Clone, Copy, Debug, PartialEq, Eq)]
233struct ModifierFingerprints {
234 strict: u64,
235 structural: u64,
236}
237
238#[inline]
239fn mix_fingerprint_bits(mut value: u64) -> u64 {
240 value ^= value >> 33;
241 value = value.wrapping_mul(0xff51_afd7_ed55_8ccd);
242 value ^= value >> 33;
243 value = value.wrapping_mul(0xc4ce_b9fe_1a85_ec53);
244 value ^ (value >> 33)
245}
246
247#[inline]
248fn fold_fingerprint(state: u64, value: u64) -> u64 {
249 mix_fingerprint_bits(state ^ value.wrapping_add(FINGERPRINT_SEQUENCE_MUL))
250 .wrapping_mul(FINGERPRINT_SEQUENCE_MUL)
251}
252
253#[inline]
254fn empty_fingerprints() -> ModifierFingerprints {
255 ModifierFingerprints {
256 strict: fold_fingerprint(FINGERPRINT_EMPTY_STRICT_SEED, FINGERPRINT_KIND_EMPTY as u64),
257 structural: fold_fingerprint(
258 FINGERPRINT_EMPTY_STRUCTURAL_SEED,
259 FINGERPRINT_KIND_EMPTY as u64,
260 ),
261 }
262}
263
264#[inline]
265fn single_fingerprint_seed() -> ModifierFingerprints {
266 let strict = fold_fingerprint(
267 FINGERPRINT_SINGLE_STRICT_SEED,
268 FINGERPRINT_KIND_SINGLE as u64,
269 );
270 let structural = fold_fingerprint(
271 FINGERPRINT_SINGLE_STRUCTURAL_SEED,
272 FINGERPRINT_KIND_SINGLE as u64,
273 );
274 ModifierFingerprints { strict, structural }
275}
276
277#[inline]
278fn element_common_fingerprint(element: &DynModifierElement) -> u64 {
279 let mut hasher = default::new();
280 element.element_type().hash(&mut hasher);
281 element.capabilities().bits().hash(&mut hasher);
282 hasher.finish()
283}
284
285#[inline]
286fn element_fingerprints(element: &DynModifierElement) -> ModifierFingerprints {
287 let common = element_common_fingerprint(element);
288 let requires_update = element.requires_update();
289 let strict_payload = if requires_update {
290 let element_ptr = Rc::as_ptr(element) as *const () as usize as u64;
291 element_ptr ^ FINGERPRINT_STRICT_UPDATE_TAG
292 } else {
293 element.hash_code()
294 };
295 let strict = mix_fingerprint_bits(common ^ strict_payload);
296
297 let is_draw_only = element.capabilities() == NodeCapabilities::DRAW;
298 let structural_payload = if is_draw_only {
299 FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG
300 } else {
301 element.hash_code()
302 };
303 let structural = mix_fingerprint_bits(common ^ structural_payload);
304
305 ModifierFingerprints { strict, structural }
306}
307
308#[inline]
309fn append_fingerprints(
310 mut fingerprints: ModifierFingerprints,
311 elements: &[DynModifierElement],
312) -> ModifierFingerprints {
313 for element in elements {
314 let element_fingerprints = element_fingerprints(element);
315 fingerprints.strict = fold_fingerprint(fingerprints.strict, element_fingerprints.strict);
316 fingerprints.structural =
317 fold_fingerprint(fingerprints.structural, element_fingerprints.structural);
318 }
319 fingerprints
320}
321
322fn single_fingerprints(elements: &[DynModifierElement]) -> ModifierFingerprints {
323 append_fingerprints(single_fingerprint_seed(), elements)
324}
325
326pub struct ModifierElementIterator<'a> {
329 inner: std::slice::Iter<'a, DynModifierElement>,
330}
331
332impl<'a> Iterator for ModifierElementIterator<'a> {
333 type Item = &'a DynModifierElement;
334
335 #[inline]
336 fn next(&mut self) -> Option<Self::Item> {
337 self.inner.next()
338 }
339
340 #[inline]
341 fn size_hint(&self) -> (usize, Option<usize>) {
342 self.inner.size_hint()
343 }
344}
345
346impl ExactSizeIterator for ModifierElementIterator<'_> {}
347
348pub(crate) struct ModifierInspectorIterator<'a> {
350 inner: std::slice::Iter<'a, InspectorMetadata>,
351}
352
353impl<'a> Iterator for ModifierInspectorIterator<'a> {
354 type Item = &'a InspectorMetadata;
355
356 #[inline]
357 fn next(&mut self) -> Option<Self::Item> {
358 self.inner.next()
359 }
360
361 #[inline]
362 fn size_hint(&self) -> (usize, Option<usize>) {
363 self.inner.size_hint()
364 }
365}
366
367impl ExactSizeIterator for ModifierInspectorIterator<'_> {}
368
369#[derive(Clone)]
387pub struct Modifier {
388 kind: ModifierKind,
389 strict_fingerprint: u64,
390 structural_fingerprint: u64,
391 element_count: usize,
392}
393
394impl Default for Modifier {
395 fn default() -> Self {
396 let fingerprints = empty_fingerprints();
397 Self {
398 kind: ModifierKind::Empty,
399 strict_fingerprint: fingerprints.strict,
400 structural_fingerprint: fingerprints.structural,
401 element_count: 0,
402 }
403 }
404}
405
406impl Modifier {
407 pub fn empty() -> Self {
408 Self::default()
409 }
410
411 pub fn from_element<E>(element: E) -> Self
413 where
414 E: ModifierNodeElement,
415 {
416 Self::with_element(element)
417 }
418
419 pub fn clip_to_bounds(self) -> Self {
423 let modifier = Self::with_element(ClipToBoundsElement::new()).with_inspector_metadata(
424 inspector_metadata("clipToBounds", |info| {
425 info.add_property("clipToBounds", "true");
426 }),
427 );
428 self.then(modifier)
429 }
430
431 pub fn modifier_local_provider<T, F>(self, key: ModifierLocalKey<T>, value: F) -> Self
432 where
433 T: 'static,
434 F: Fn() -> T + 'static,
435 {
436 let element = ModifierLocalProviderElement::new(key, value);
437 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
438 self.then(modifier)
439 }
440
441 pub fn modifier_local_consumer<F>(self, consumer: F) -> Self
442 where
443 F: for<'scope> Fn(&mut ModifierLocalReadScope<'scope>) + 'static,
444 {
445 let element = ModifierLocalConsumerElement::new(consumer);
446 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
447 self.then(modifier)
448 }
449
450 pub fn semantics<F>(self, recorder: F) -> Self
451 where
452 F: Fn(&mut SemanticsConfiguration) + 'static,
453 {
454 let mut preview = SemanticsConfiguration::default();
455 recorder(&mut preview);
456 let description = preview.content_description.clone();
457 let is_button = preview.is_button;
458 let is_clickable = preview.is_clickable;
459 let metadata = inspector_metadata("semantics", move |info| {
460 if let Some(desc) = &description {
461 info.add_property("contentDescription", desc.clone());
462 }
463 if is_button {
464 info.add_property("isButton", "true");
465 }
466 if is_clickable {
467 info.add_property("isClickable", "true");
468 }
469 });
470 let element = SemanticsElement::new(recorder);
471 let modifier =
472 Modifier::from_parts(vec![modifier_element(element)]).with_inspector_metadata(metadata);
473 self.then(modifier)
474 }
475
476 pub fn focus_target(self) -> Self {
482 let element = FocusTargetElement::new();
483 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
484 self.then(modifier)
485 }
486
487 pub fn on_focus_changed<F>(self, callback: F) -> Self
492 where
493 F: Fn(FocusState) + 'static,
494 {
495 let element = FocusTargetElement::with_callback(callback);
496 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
497 self.then(modifier)
498 }
499
500 pub fn focus_requester(self, requester: &FocusRequester) -> Self {
505 let element = FocusRequesterElement::new(requester.token());
506 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
507 self.then(modifier)
508 }
509
510 pub fn debug_chain(self, tag: &'static str) -> Self {
528 use cranpose_foundation::{ModifierNode, ModifierNodeContext, NodeCapabilities, NodeState};
529
530 #[derive(Clone)]
531 struct DebugChainElement {
532 tag: &'static str,
533 }
534
535 impl fmt::Debug for DebugChainElement {
536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537 f.debug_struct("DebugChainElement")
538 .field("tag", &self.tag)
539 .finish()
540 }
541 }
542
543 impl PartialEq for DebugChainElement {
544 fn eq(&self, other: &Self) -> bool {
545 self.tag == other.tag
546 }
547 }
548
549 impl Eq for DebugChainElement {}
550
551 impl std::hash::Hash for DebugChainElement {
552 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
553 self.tag.hash(state);
554 }
555 }
556
557 impl ModifierNodeElement for DebugChainElement {
558 type Node = DebugChainNode;
559
560 fn create(&self) -> Self::Node {
561 DebugChainNode::new(self.tag)
562 }
563
564 fn update(&self, node: &mut Self::Node) {
565 node.tag = self.tag;
566 }
567
568 fn capabilities(&self) -> NodeCapabilities {
569 NodeCapabilities::empty()
570 }
571 }
572
573 struct DebugChainNode {
574 tag: &'static str,
575 state: NodeState,
576 }
577
578 impl DebugChainNode {
579 fn new(tag: &'static str) -> Self {
580 Self {
581 tag,
582 state: NodeState::new(),
583 }
584 }
585 }
586
587 impl ModifierNode for DebugChainNode {
588 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
589 eprintln!("[debug_chain:{}] Modifier chain attached", self.tag);
590 }
591
592 fn on_detach(&mut self) {
593 eprintln!("[debug_chain:{}] Modifier chain detached", self.tag);
594 }
595
596 fn on_reset(&mut self) {
597 eprintln!("[debug_chain:{}] Modifier chain reset", self.tag);
598 }
599 }
600
601 impl cranpose_foundation::DelegatableNode for DebugChainNode {
602 fn node_state(&self) -> &NodeState {
603 &self.state
604 }
605 }
606
607 let element = DebugChainElement { tag };
608 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
609 self.then(modifier)
610 .with_inspector_metadata(inspector_metadata("debugChain", move |info| {
611 info.add_property("tag", tag);
612 }))
613 }
614
615 pub fn then(&self, next: Modifier) -> Modifier {
620 if self.is_trivially_empty() {
621 return next;
622 }
623 if next.is_trivially_empty() {
624 return self.clone();
625 }
626
627 let Some((self_elements, self_inspector)) = self.single_parts() else {
628 return next;
629 };
630 let Some((next_elements, next_inspector)) = next.single_parts() else {
631 return self.clone();
632 };
633
634 let mut merged_elements = Vec::with_capacity(self_elements.len() + next_elements.len());
635 merged_elements.extend_from_slice(self_elements);
636 merged_elements.extend_from_slice(next_elements);
637
638 let mut merged_inspector = Vec::with_capacity(self_inspector.len() + next_inspector.len());
639 merged_inspector.extend_from_slice(self_inspector);
640 merged_inspector.extend_from_slice(next_inspector);
641
642 let fingerprints = append_fingerprints(
643 ModifierFingerprints {
644 strict: self.strict_fingerprint,
645 structural: self.structural_fingerprint,
646 },
647 next_elements,
648 );
649 Modifier {
650 kind: ModifierKind::Single {
651 elements: Rc::new(merged_elements),
652 inspector: Rc::new(merged_inspector),
653 },
654 strict_fingerprint: fingerprints.strict,
655 structural_fingerprint: fingerprints.structural,
656 element_count: self.element_count + next.element_count,
657 }
658 }
659
660 pub(crate) fn iter_elements(&self) -> ModifierElementIterator<'_> {
662 match &self.kind {
663 ModifierKind::Empty => ModifierElementIterator { inner: [].iter() },
664 ModifierKind::Single { elements, .. } => ModifierElementIterator {
665 inner: elements.iter(),
666 },
667 }
668 }
669
670 pub(crate) fn iter_inspector_metadata(&self) -> ModifierInspectorIterator<'_> {
671 match &self.kind {
672 ModifierKind::Empty => ModifierInspectorIterator { inner: [].iter() },
673 ModifierKind::Single { inspector, .. } => ModifierInspectorIterator {
674 inner: inspector.iter(),
675 },
676 }
677 }
678
679 #[cfg(test)]
683 pub(crate) fn elements(&self) -> Vec<DynModifierElement> {
684 match &self.kind {
685 ModifierKind::Empty => Vec::new(),
686 ModifierKind::Single { elements, .. } => elements.as_ref().clone(),
687 }
688 }
689
690 pub(crate) fn inspector_metadata(&self) -> Vec<InspectorMetadata> {
692 match &self.kind {
693 ModifierKind::Empty => Vec::new(),
694 ModifierKind::Single { inspector, .. } => inspector.as_ref().clone(),
695 }
696 }
697
698 pub(crate) fn rehouse_for_live_compaction(&self) -> Self {
699 match &self.kind {
700 ModifierKind::Empty => Self::default(),
701 ModifierKind::Single {
702 elements,
703 inspector,
704 } => Self {
705 kind: ModifierKind::Single {
706 elements: Rc::new(elements.iter().cloned().collect()),
707 inspector: Rc::new(inspector.as_ref().clone()),
708 },
709 strict_fingerprint: self.strict_fingerprint,
710 structural_fingerprint: self.structural_fingerprint,
711 element_count: self.element_count,
712 },
713 }
714 }
715
716 pub fn total_padding(&self) -> f32 {
717 let padding = self.padding_values();
718 padding
719 .left
720 .max(padding.right)
721 .max(padding.top)
722 .max(padding.bottom)
723 }
724
725 pub fn explicit_size(&self) -> Option<Size> {
726 let props = self.layout_properties();
727 match (props.width, props.height) {
728 (DimensionConstraint::Points(width), DimensionConstraint::Points(height)) => {
729 Some(Size { width, height })
730 }
731 _ => None,
732 }
733 }
734
735 pub fn padding_values(&self) -> EdgeInsets {
736 self.resolved_modifiers().padding()
737 }
738
739 pub(crate) fn layout_properties(&self) -> LayoutProperties {
740 self.resolved_modifiers().layout_properties()
741 }
742
743 pub fn box_alignment(&self) -> Option<Alignment> {
744 self.layout_properties().box_alignment()
745 }
746
747 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
748 self.layout_properties().column_alignment()
749 }
750
751 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
752 self.layout_properties().row_alignment()
753 }
754
755 pub fn draw_commands(&self) -> Vec<DrawCommand> {
756 collect_slices_from_modifier(self).draw_commands().to_vec()
757 }
758
759 pub fn clips_to_bounds(&self) -> bool {
760 collect_slices_from_modifier(self).clip_to_bounds()
761 }
762
763 pub fn collect_inspector_records(&self) -> Vec<ModifierInspectorRecord> {
765 self.inspector_metadata()
766 .iter()
767 .map(|metadata| metadata.to_record())
768 .collect()
769 }
770
771 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
772 let mut handle = ModifierChainHandle::new();
773 let _ = handle.update(self);
774 handle.resolved_modifiers()
775 }
776
777 pub(crate) fn with_element<E>(element: E) -> Self
778 where
779 E: ModifierNodeElement,
780 {
781 let dyn_element = modifier_element(element);
782 Self::from_parts(vec![dyn_element])
783 }
784
785 pub(crate) fn from_parts(elements: Vec<DynModifierElement>) -> Self {
786 if elements.is_empty() {
787 Self::default()
788 } else {
789 let element_count = elements.len();
790 let fingerprints = single_fingerprints(elements.as_slice());
791 Self {
792 kind: ModifierKind::Single {
793 elements: Rc::new(elements),
794 inspector: Rc::new(Vec::new()),
795 },
796 strict_fingerprint: fingerprints.strict,
797 structural_fingerprint: fingerprints.structural,
798 element_count,
799 }
800 }
801 }
802
803 fn is_trivially_empty(&self) -> bool {
804 matches!(self.kind, ModifierKind::Empty)
805 }
806
807 fn single_parts(&self) -> Option<(&[DynModifierElement], &[InspectorMetadata])> {
808 match &self.kind {
809 ModifierKind::Empty => None,
810 ModifierKind::Single {
811 elements,
812 inspector,
813 } => Some((elements.as_slice(), inspector.as_slice())),
814 }
815 }
816
817 pub(crate) fn with_inspector_metadata(self, metadata: InspectorMetadata) -> Self {
818 if metadata.is_empty() {
819 return self;
820 }
821 match self.kind {
822 ModifierKind::Empty => self,
823 ModifierKind::Single {
824 elements,
825 inspector,
826 } => {
827 let mut new_inspector = inspector.as_ref().clone();
828 new_inspector.push(metadata);
829 Self {
830 kind: ModifierKind::Single {
831 elements,
832 inspector: Rc::new(new_inspector),
833 },
834 strict_fingerprint: self.strict_fingerprint,
835 structural_fingerprint: self.structural_fingerprint,
836 element_count: self.element_count,
837 }
838 }
839 }
840 }
841
842 pub fn structural_eq(&self, other: &Self) -> bool {
847 self.eq_internal(other, false)
848 }
849
850 fn eq_internal(&self, other: &Self, consider_always_update: bool) -> bool {
851 if self.element_count != other.element_count {
852 return false;
853 }
854 if consider_always_update {
855 if self.strict_fingerprint != other.strict_fingerprint {
856 return false;
857 }
858 } else if self.structural_fingerprint != other.structural_fingerprint {
859 return false;
860 }
861
862 match (&self.kind, &other.kind) {
863 (ModifierKind::Empty, ModifierKind::Empty) => true,
864 (
865 ModifierKind::Single {
866 elements: e1,
867 inspector: _,
868 },
869 ModifierKind::Single {
870 elements: e2,
871 inspector: _,
872 },
873 ) => {
874 if Rc::ptr_eq(e1, e2) {
875 return true;
876 }
877
878 if e1.len() != e2.len() {
879 return false;
880 }
881
882 for (a, b) in e1.iter().zip(e2.iter()) {
883 if !consider_always_update
887 && a.element_type() == b.element_type()
888 && a.capabilities() == NodeCapabilities::DRAW
889 && b.capabilities() == NodeCapabilities::DRAW
890 {
891 continue;
892 }
893
894 if consider_always_update && (a.requires_update() || b.requires_update()) {
895 if !Rc::ptr_eq(a, b) {
896 return false;
897 }
898 continue;
899 }
900
901 if !a.equals_element(&**b) {
902 return false;
903 }
904 }
905
906 true
907 }
908 _ => false,
909 }
910 }
911}
912
913impl PartialEq for Modifier {
914 fn eq(&self, other: &Self) -> bool {
915 self.eq_internal(other, true)
916 }
917}
918
919impl Eq for Modifier {}
920
921impl fmt::Display for Modifier {
922 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
923 match &self.kind {
924 ModifierKind::Empty => write!(f, "Modifier.empty"),
925 ModifierKind::Single { elements, .. } => {
926 if elements.is_empty() {
927 return write!(f, "Modifier.empty");
928 }
929 write!(f, "Modifier[")?;
930 for (index, element) in elements.iter().enumerate() {
931 if index > 0 {
932 write!(f, ", ")?;
933 }
934 let name = element.inspector_name();
935 let mut properties = Vec::new();
936 element.record_inspector_properties(&mut |prop, value| {
937 properties.push(format!("{prop}={value}"));
938 });
939 if properties.is_empty() {
940 write!(f, "{name}")?;
941 } else {
942 write!(f, "{name}({})", properties.join(", "))?;
943 }
944 }
945 write!(f, "]")
946 }
947 }
948 }
949}
950
951impl fmt::Debug for Modifier {
952 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
953 fmt::Display::fmt(self, f)
954 }
955}
956
957#[derive(Clone, Copy, Debug, PartialEq)]
958pub struct ResolvedBackground {
959 color: Color,
960 shape: Option<RoundedCornerShape>,
961}
962
963impl ResolvedBackground {
964 pub fn new(color: Color, shape: Option<RoundedCornerShape>) -> Self {
965 Self { color, shape }
966 }
967
968 pub fn color(&self) -> Color {
969 self.color
970 }
971
972 pub fn shape(&self) -> Option<RoundedCornerShape> {
973 self.shape
974 }
975
976 pub fn set_shape(&mut self, shape: Option<RoundedCornerShape>) {
977 self.shape = shape;
978 }
979}
980
981#[derive(Clone, Copy, Debug, PartialEq, Default)]
982pub struct ResolvedModifiers {
983 padding: EdgeInsets,
984 layout: LayoutProperties,
985 offset: Point,
986}
987
988impl ResolvedModifiers {
989 pub fn padding(&self) -> EdgeInsets {
990 self.padding
991 }
992
993 pub fn layout_properties(&self) -> LayoutProperties {
994 self.layout
995 }
996
997 pub fn offset(&self) -> Point {
998 self.offset
999 }
1000
1001 pub(crate) fn set_padding(&mut self, padding: EdgeInsets) {
1002 self.padding = padding;
1003 }
1004
1005 pub(crate) fn set_layout_properties(&mut self, layout: LayoutProperties) {
1006 self.layout = layout;
1007 }
1008
1009 pub(crate) fn set_offset(&mut self, offset: Point) {
1010 self.offset = offset;
1011 }
1012}
1013
1014#[derive(Clone, Copy, Debug, Default, PartialEq)]
1015pub enum DimensionConstraint {
1016 #[default]
1017 Unspecified,
1018 Points(f32),
1019 Fraction(f32),
1020 Intrinsic(IntrinsicSize),
1021}
1022
1023#[derive(Clone, Copy, Debug, Default, PartialEq)]
1024pub struct LayoutWeight {
1025 pub weight: f32,
1026 pub fill: bool,
1027}
1028
1029#[derive(Clone, Copy, Debug, Default, PartialEq)]
1030pub struct LayoutProperties {
1031 padding: EdgeInsets,
1032 width: DimensionConstraint,
1033 height: DimensionConstraint,
1034 min_width: Option<f32>,
1035 min_height: Option<f32>,
1036 max_width: Option<f32>,
1037 max_height: Option<f32>,
1038 weight: Option<LayoutWeight>,
1039 box_alignment: Option<Alignment>,
1040 column_alignment: Option<HorizontalAlignment>,
1041 row_alignment: Option<VerticalAlignment>,
1042}
1043
1044impl LayoutProperties {
1045 pub fn padding(&self) -> EdgeInsets {
1046 self.padding
1047 }
1048
1049 pub fn width(&self) -> DimensionConstraint {
1050 self.width
1051 }
1052
1053 pub fn height(&self) -> DimensionConstraint {
1054 self.height
1055 }
1056
1057 pub fn min_width(&self) -> Option<f32> {
1058 self.min_width
1059 }
1060
1061 pub fn min_height(&self) -> Option<f32> {
1062 self.min_height
1063 }
1064
1065 pub fn max_width(&self) -> Option<f32> {
1066 self.max_width
1067 }
1068
1069 pub fn max_height(&self) -> Option<f32> {
1070 self.max_height
1071 }
1072
1073 pub fn weight(&self) -> Option<LayoutWeight> {
1074 self.weight
1075 }
1076
1077 pub fn box_alignment(&self) -> Option<Alignment> {
1078 self.box_alignment
1079 }
1080
1081 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
1082 self.column_alignment
1083 }
1084
1085 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
1086 self.row_alignment
1087 }
1088}
1089
1090#[cfg(test)]
1091#[path = "tests/modifier_tests.rs"]
1092mod tests;