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