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