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