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