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 selectable;
34mod semantics;
35mod shadow;
36mod size;
37mod slices;
38mod toggleable;
39mod weight;
40
41#[allow(unused_imports)]
42pub use chain::{ModifierChainHandle, ModifierChainInspectorNode, ModifierLocalsHandle};
43pub use cranpose_foundation::{
44 AnyModifierElement, DynModifierElement, FocusState, PointerEvent, PointerEventKind,
45 PointerSource, RotaryScrollEvent, SemanticsConfiguration, modifier_element,
46};
47use cranpose_foundation::{ModifierNodeElement, NodeCapabilities, ProgressBarRangeInfo};
48#[allow(unused_imports)]
49pub use cranpose_ui_graphics::{
50 BlendMode, BlurredEdgeTreatment, Brush, Color, ColorFilter, CompositingStrategy, CornerRadii,
51 CutDirection, Dp, DpOffset, EdgeInsets, GradientCutMaskSpec, GradientFadeMaskSpec,
52 GraphicsLayer, LayerShape, Point, Rect, RenderEffect, RoundedCornerShape, RuntimeShader,
53 Shadow, ShadowScope, Size, TransformOrigin,
54};
55use cranpose_ui_layout::{Alignment, HorizontalAlignment, IntrinsicSize, VerticalAlignment};
56use focus::FocusTargetElement;
57#[allow(unused_imports)]
58pub use focus::{FocusDirection, FocusRequestError, FocusRequester, FocusRequesterElement};
59pub use graphics_layer::GlassMaterial;
60pub(crate) use local::{
61 ModifierLocalAncestorResolver, ModifierLocalSource, ModifierLocalToken, ResolvedModifierLocal,
62};
63use local::{ModifierLocalConsumerElement, ModifierLocalProviderElement};
64#[allow(unused_imports)]
65pub use local::{ModifierLocalKey, ModifierLocalReadScope};
66#[allow(unused_imports)]
67pub use pointer_input::{AwaitPointerEventScope, PointerInputScope};
68pub use rotary_input::RotaryInputModifierNode;
69#[cfg(test)]
70pub(crate) use scroll::lazy_scroll_semantics;
71#[cfg(feature = "test-helpers")]
72pub use scroll::{last_fling_velocity, reset_last_fling_velocity};
73use semantics::SemanticsElement;
74pub use semantics::{
75 SemanticsRequester, SemanticsRequesterElement, collect_semantics_from_chain,
76 collect_semantics_from_modifier,
77};
78pub use slices::{
79 ModifierNodeSlices, ModifierNodeSlicesDebugStats, collect_modifier_slices,
80 collect_modifier_slices_into, collect_slices_from_modifier,
81};
82
83pub use crate::draw::{DrawCacheBuilder, DrawCommand};
84use crate::modifier_nodes::ClipToBoundsElement;
85
86#[derive(Clone, Debug, Default)]
87pub struct InspectorInfo {
88 properties: Vec<InspectorProperty>,
89}
90
91impl InspectorInfo {
92 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn add_property<V: Into<String>>(&mut self, name: &'static str, value: V) {
97 self.properties.push(InspectorProperty {
98 name,
99 value: value.into(),
100 });
101 }
102
103 pub fn properties(&self) -> &[InspectorProperty] {
104 &self.properties
105 }
106
107 pub fn is_empty(&self) -> bool {
108 self.properties.is_empty()
109 }
110
111 pub fn add_dimension(&mut self, name: &'static str, constraint: DimensionConstraint) {
112 self.add_property(name, describe_dimension(constraint));
113 }
114
115 pub fn add_offset_components(
116 &mut self,
117 x_name: &'static str,
118 y_name: &'static str,
119 offset: Point,
120 ) {
121 self.add_property(x_name, offset.x.to_string());
122 self.add_property(y_name, offset.y.to_string());
123 }
124
125 pub fn add_alignment<A>(&mut self, name: &'static str, alignment: A)
126 where
127 A: fmt::Debug,
128 {
129 self.add_property(name, format!("{alignment:?}"));
130 }
131}
132
133#[derive(Clone, Debug, PartialEq)]
134pub struct InspectorProperty {
135 pub name: &'static str,
136 pub value: String,
137}
138
139#[derive(Clone, Debug, PartialEq)]
140pub struct ModifierInspectorRecord {
141 pub name: &'static str,
142 pub properties: Vec<InspectorProperty>,
143}
144
145#[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() {
187 return InspectorMetadata::new(name, |_| {});
188 }
189 InspectorMetadata::new(name, recorder)
190}
191
192pub(crate) fn modifier_debug_enabled() -> bool {
193 #[cfg(not(target_arch = "wasm32"))]
194 {
195 cranpose_core::env_flag!("COMPOSE_DEBUG_MODIFIERS")
196 }
197 #[cfg(target_arch = "wasm32")]
198 {
199 false
200 }
201}
202
203fn inspector_metadata_enabled() -> bool {
204 cfg!(test) || modifier_debug_enabled()
205}
206
207#[derive(Clone)]
208enum ModifierKind {
209 Empty,
210 Single {
211 elements: Rc<Vec<DynModifierElement>>,
212 inspector: Rc<Vec<InspectorMetadata>>,
213 },
214}
215
216const FINGERPRINT_KIND_EMPTY: u8 = 0;
217const FINGERPRINT_KIND_SINGLE: u8 = 1;
218
219const FINGERPRINT_EMPTY_STRICT_SEED: u64 = 0x243f_6a88_85a3_08d3;
220const FINGERPRINT_EMPTY_STRUCTURAL_SEED: u64 = 0x1319_8a2e_0370_7344;
221const FINGERPRINT_SINGLE_STRICT_SEED: u64 = 0xa409_3822_299f_31d0;
222const FINGERPRINT_SINGLE_STRUCTURAL_SEED: u64 = 0x082e_fa98_ec4e_6c89;
223const FINGERPRINT_SEQUENCE_MUL: u64 = 0x9e37_79b1_85eb_ca87;
224const FINGERPRINT_STRICT_UPDATE_TAG: u64 = 0xdbe6_d5d5_fe4c_ce2f;
225const FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG: u64 = 0x94d0_49bb_1331_11eb;
226
227#[derive(Clone, Copy, Debug, PartialEq, Eq)]
228struct ModifierFingerprints {
229 strict: u64,
230 structural: u64,
231}
232
233#[inline]
234fn mix_fingerprint_bits(mut value: u64) -> u64 {
235 value ^= value >> 33;
236 value = value.wrapping_mul(0xff51_afd7_ed55_8ccd);
237 value ^= value >> 33;
238 value = value.wrapping_mul(0xc4ce_b9fe_1a85_ec53);
239 value ^ (value >> 33)
240}
241
242#[inline]
243fn fold_fingerprint(state: u64, value: u64) -> u64 {
244 mix_fingerprint_bits(state ^ value.wrapping_add(FINGERPRINT_SEQUENCE_MUL))
245 .wrapping_mul(FINGERPRINT_SEQUENCE_MUL)
246}
247
248#[inline]
249fn empty_fingerprints() -> ModifierFingerprints {
250 ModifierFingerprints {
251 strict: fold_fingerprint(FINGERPRINT_EMPTY_STRICT_SEED, FINGERPRINT_KIND_EMPTY as u64),
252 structural: fold_fingerprint(
253 FINGERPRINT_EMPTY_STRUCTURAL_SEED,
254 FINGERPRINT_KIND_EMPTY as u64,
255 ),
256 }
257}
258
259#[inline]
260fn single_fingerprint_seed() -> ModifierFingerprints {
261 let strict = fold_fingerprint(
262 FINGERPRINT_SINGLE_STRICT_SEED,
263 FINGERPRINT_KIND_SINGLE as u64,
264 );
265 let structural = fold_fingerprint(
266 FINGERPRINT_SINGLE_STRUCTURAL_SEED,
267 FINGERPRINT_KIND_SINGLE as u64,
268 );
269 ModifierFingerprints { strict, structural }
270}
271
272#[inline]
273fn element_common_fingerprint(element: &DynModifierElement) -> u64 {
274 let mut hasher = default::new();
275 element.element_type().hash(&mut hasher);
276 element.capabilities().bits().hash(&mut hasher);
277 hasher.finish()
278}
279
280#[inline]
281fn element_fingerprints(element: &DynModifierElement) -> ModifierFingerprints {
282 let common = element_common_fingerprint(element);
283 let requires_update = element.requires_update();
284 let strict_payload = if requires_update {
285 let element_ptr = Rc::as_ptr(element) as *const () as usize as u64;
286 element_ptr ^ FINGERPRINT_STRICT_UPDATE_TAG
287 } else {
288 element.hash_code()
289 };
290 let strict = mix_fingerprint_bits(common ^ strict_payload);
291
292 let is_draw_only = element.capabilities() == NodeCapabilities::DRAW;
293 let structural_payload = if is_draw_only {
294 FINGERPRINT_STRUCTURAL_DRAW_ONLY_TAG
295 } else {
296 element.hash_code()
297 };
298 let structural = mix_fingerprint_bits(common ^ structural_payload);
299
300 ModifierFingerprints { strict, structural }
301}
302
303#[inline]
304fn append_fingerprints(
305 mut fingerprints: ModifierFingerprints,
306 elements: &[DynModifierElement],
307) -> ModifierFingerprints {
308 for element in elements {
309 let element_fingerprints = element_fingerprints(element);
310 fingerprints.strict = fold_fingerprint(fingerprints.strict, element_fingerprints.strict);
311 fingerprints.structural =
312 fold_fingerprint(fingerprints.structural, element_fingerprints.structural);
313 }
314 fingerprints
315}
316
317fn single_fingerprints(elements: &[DynModifierElement]) -> ModifierFingerprints {
318 append_fingerprints(single_fingerprint_seed(), elements)
319}
320
321pub struct ModifierElementIterator<'a> {
322 inner: std::slice::Iter<'a, DynModifierElement>,
323}
324
325impl<'a> Iterator for ModifierElementIterator<'a> {
326 type Item = &'a DynModifierElement;
327
328 #[inline]
329 fn next(&mut self) -> Option<Self::Item> {
330 self.inner.next()
331 }
332
333 #[inline]
334 fn size_hint(&self) -> (usize, Option<usize>) {
335 self.inner.size_hint()
336 }
337}
338
339impl ExactSizeIterator for ModifierElementIterator<'_> {}
340
341pub(crate) struct ModifierInspectorIterator<'a> {
342 inner: std::slice::Iter<'a, InspectorMetadata>,
343}
344
345impl<'a> Iterator for ModifierInspectorIterator<'a> {
346 type Item = &'a InspectorMetadata;
347
348 #[inline]
349 fn next(&mut self) -> Option<Self::Item> {
350 self.inner.next()
351 }
352
353 #[inline]
354 fn size_hint(&self) -> (usize, Option<usize>) {
355 self.inner.size_hint()
356 }
357}
358
359impl ExactSizeIterator for ModifierInspectorIterator<'_> {}
360
361#[derive(Clone)]
379pub struct Modifier {
380 kind: ModifierKind,
381 strict_fingerprint: u64,
382 structural_fingerprint: u64,
383 element_count: usize,
384}
385
386impl Default for Modifier {
387 fn default() -> Self {
388 let fingerprints = empty_fingerprints();
389 Self {
390 kind: ModifierKind::Empty,
391 strict_fingerprint: fingerprints.strict,
392 structural_fingerprint: fingerprints.structural,
393 element_count: 0,
394 }
395 }
396}
397
398impl Modifier {
399 pub fn empty() -> Self {
400 Self::default()
401 }
402
403 pub fn from_element<E>(element: E) -> Self
405 where
406 E: ModifierNodeElement,
407 {
408 Self::with_element(element)
409 }
410
411 pub fn clip_to_bounds(self) -> Self {
415 let modifier = Self::with_element(ClipToBoundsElement::new()).with_inspector_metadata(
416 inspector_metadata("clipToBounds", |info| {
417 info.add_property("clipToBounds", "true");
418 }),
419 );
420 self.then(modifier)
421 }
422
423 pub fn modifier_local_provider<T, F>(self, key: ModifierLocalKey<T>, value: F) -> Self
424 where
425 T: 'static,
426 F: Fn() -> T + 'static,
427 {
428 let element = ModifierLocalProviderElement::new(key, value);
429 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
430 self.then(modifier)
431 }
432
433 pub fn modifier_local_consumer<F>(self, consumer: F) -> Self
434 where
435 F: for<'scope> Fn(&mut ModifierLocalReadScope<'scope>) + 'static,
436 {
437 let element = ModifierLocalConsumerElement::new(consumer);
438 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
439 self.then(modifier)
440 }
441
442 pub fn semantics_spec(self, spec: cranpose_foundation::SemanticsSpec) -> Self {
453 self.semantics(move |config: &mut SemanticsConfiguration| config.merge(&spec))
454 }
455 pub fn semantics<F>(self, recorder: F) -> Self
456 where
457 F: Fn(&mut SemanticsConfiguration) + 'static,
458 {
459 let recorder: std::rc::Rc<dyn Fn(&mut SemanticsConfiguration)> = std::rc::Rc::new(recorder);
460 let metadata = if inspector_metadata_enabled() {
461 let mut preview = SemanticsConfiguration::default();
462 recorder(&mut preview);
463 let description = preview.content_description.clone();
464 let state_description = preview.state_description.clone();
465 let role = preview.role;
466 let is_clickable = preview.is_activatable();
467 let canvas_children = preview.canvas_children.len();
468 inspector_metadata("semantics", move |info| {
469 if let Some(desc) = &description {
470 info.add_property("contentDescription", desc.clone());
471 }
472 if let Some(state) = &state_description {
473 info.add_property("stateDescription", state.clone());
474 }
475 if let Some(role) = role {
476 info.add_property("role", format!("{role:?}"));
477 }
478 if is_clickable {
479 info.add_property("isClickable", "true");
480 }
481 if canvas_children > 0 {
482 info.add_property("canvasSemanticsChildren", canvas_children.to_string());
483 }
484 })
485 } else {
486 inspector_metadata("semantics", |_| {})
487 };
488 let element = SemanticsElement::new(recorder);
489 let modifier =
490 Modifier::from_parts(vec![modifier_element(element)]).with_inspector_metadata(metadata);
491 self.then(modifier)
492 }
493
494 pub fn progress_semantics(self, current: f32, start: f32, end: f32, steps: u32) -> Self {
503 let info = ProgressBarRangeInfo::new(current, start, end, steps);
504 self.semantics(move |config| config.progress = Some(info))
505 }
506
507 pub fn dropdown_list(self) -> Self {
511 self.role(cranpose_foundation::SemanticsWidgetRole::DropdownList)
512 }
513
514 pub fn value_picker(self) -> Self {
517 self.role(cranpose_foundation::SemanticsWidgetRole::ValuePicker)
518 }
519
520 pub fn expand(self, action: impl Fn() -> bool + 'static) -> Self {
525 let action = cranpose_foundation::SemanticsExpand::new(action);
526 self.semantics(move |config| config.expand = Some(action.clone()))
527 }
528
529 pub fn collapse(self, action: impl Fn() -> bool + 'static) -> Self {
533 let action = cranpose_foundation::SemanticsExpand::new(action);
534 self.semantics(move |config| config.collapse = Some(action.clone()))
535 }
536
537 pub fn traversal_index(self, index: f32) -> Self {
543 self.semantics(move |config| config.traversal_index = index)
544 }
545
546 pub fn password(self) -> Self {
551 self.semantics(|config| config.password = true)
552 }
553
554 pub fn error(self, message: impl Into<String>) -> Self {
558 let message = message.into();
559 self.semantics(move |config| config.error = Some(message.clone()))
560 }
561
562 pub fn pane_title(self, title: impl Into<String>) -> Self {
566 let title = title.into();
567 self.semantics(move |config| config.pane_title = Some(title.clone()))
568 }
569
570 pub fn selectable_group(self) -> Self {
575 self.semantics(|config| config.selectable_group = true)
576 }
577
578 pub fn merge_descendants(self) -> Self {
583 self.semantics(|config| config.merge_descendants = true)
584 }
585
586 pub fn hide_from_accessibility(self) -> Self {
591 self.semantics(|config| config.hidden = true)
592 }
593
594 pub fn heading(self) -> Self {
599 self.role(cranpose_foundation::SemanticsWidgetRole::Header)
600 }
601
602 pub fn role(self, role: cranpose_foundation::SemanticsWidgetRole) -> Self {
607 self.semantics(move |config| config.role = Some(role))
608 }
609
610 pub fn live_region(self, mode: cranpose_foundation::LiveRegionMode) -> Self {
616 self.semantics(move |config| config.live_region = Some(mode))
617 }
618
619 pub fn content_description(self, description: impl Into<String>) -> Self {
624 let description = description.into();
625 self.semantics(move |config| config.content_description = Some(description.clone()))
626 }
627
628 pub fn focus_target(self) -> Self {
634 let element = FocusTargetElement::new();
635 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
636 self.then(modifier)
637 }
638
639 pub fn on_focus_changed<F>(self, callback: F) -> Self
644 where
645 F: Fn(FocusState) + 'static,
646 {
647 let element = FocusTargetElement::with_callback(callback);
648 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
649 self.then(modifier)
650 }
651
652 pub fn focus_requester(self, requester: &FocusRequester) -> Self {
659 let element = FocusRequesterElement::new(requester.clone());
660 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
661 self.then(modifier)
662 }
663
664 pub fn focusable(self) -> Self {
673 self.focus_target()
674 }
675
676 pub fn semantics_requester(self, requester: &SemanticsRequester) -> Self {
684 let element = SemanticsRequesterElement::new(requester.clone());
685 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
686 self.then(modifier)
687 }
688
689 pub fn debug_chain(self, tag: &'static str) -> Self {
707 use cranpose_foundation::{ModifierNode, ModifierNodeContext, NodeCapabilities, NodeState};
708
709 #[derive(Clone)]
710 struct DebugChainElement {
711 tag: &'static str,
712 }
713
714 impl fmt::Debug for DebugChainElement {
715 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
716 f.debug_struct("DebugChainElement")
717 .field("tag", &self.tag)
718 .finish()
719 }
720 }
721
722 impl PartialEq for DebugChainElement {
723 fn eq(&self, other: &Self) -> bool {
724 self.tag == other.tag
725 }
726 }
727
728 impl Eq for DebugChainElement {}
729
730 impl std::hash::Hash for DebugChainElement {
731 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
732 self.tag.hash(state);
733 }
734 }
735
736 impl ModifierNodeElement for DebugChainElement {
737 type Node = DebugChainNode;
738
739 fn create(&self) -> Self::Node {
740 DebugChainNode::new(self.tag)
741 }
742
743 fn update(&self, node: &mut Self::Node) {
744 node.tag = self.tag;
745 }
746
747 fn capabilities(&self) -> NodeCapabilities {
748 NodeCapabilities::empty()
749 }
750 }
751
752 struct DebugChainNode {
753 tag: &'static str,
754 state: NodeState,
755 }
756
757 impl DebugChainNode {
758 fn new(tag: &'static str) -> Self {
759 Self {
760 tag,
761 state: NodeState::new(),
762 }
763 }
764 }
765
766 impl ModifierNode for DebugChainNode {
767 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
768 eprintln!("[debug_chain:{}] Modifier chain attached", self.tag);
769 }
770
771 fn on_detach(&mut self) {
772 eprintln!("[debug_chain:{}] Modifier chain detached", self.tag);
773 }
774
775 fn on_reset(&mut self) {
776 eprintln!("[debug_chain:{}] Modifier chain reset", self.tag);
777 }
778 }
779
780 impl cranpose_foundation::DelegatableNode for DebugChainNode {
781 fn node_state(&self) -> &NodeState {
782 &self.state
783 }
784 }
785
786 let element = DebugChainElement { tag };
787 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
788 self.then(modifier)
789 .with_inspector_metadata(inspector_metadata("debugChain", move |info| {
790 info.add_property("tag", tag);
791 }))
792 }
793
794 pub fn then(&self, next: Modifier) -> Modifier {
799 if self.is_trivially_empty() {
800 return next;
801 }
802 if next.is_trivially_empty() {
803 return self.clone();
804 }
805
806 let Some((self_elements, self_inspector)) = self.single_parts() else {
807 return next;
808 };
809 let Some((next_elements, next_inspector)) = next.single_parts() else {
810 return self.clone();
811 };
812
813 let mut merged_elements = Vec::with_capacity(self_elements.len() + next_elements.len());
814 merged_elements.extend_from_slice(self_elements);
815 merged_elements.extend_from_slice(next_elements);
816
817 let mut merged_inspector = Vec::with_capacity(self_inspector.len() + next_inspector.len());
818 merged_inspector.extend_from_slice(self_inspector);
819 merged_inspector.extend_from_slice(next_inspector);
820
821 let fingerprints = append_fingerprints(
822 ModifierFingerprints {
823 strict: self.strict_fingerprint,
824 structural: self.structural_fingerprint,
825 },
826 next_elements,
827 );
828 Modifier {
829 kind: ModifierKind::Single {
830 elements: Rc::new(merged_elements),
831 inspector: Rc::new(merged_inspector),
832 },
833 strict_fingerprint: fingerprints.strict,
834 structural_fingerprint: fingerprints.structural,
835 element_count: self.element_count + next.element_count,
836 }
837 }
838
839 pub(crate) fn iter_elements(&self) -> ModifierElementIterator<'_> {
840 match &self.kind {
841 ModifierKind::Empty => ModifierElementIterator { inner: [].iter() },
842 ModifierKind::Single { elements, .. } => ModifierElementIterator {
843 inner: elements.iter(),
844 },
845 }
846 }
847
848 pub(crate) fn iter_inspector_metadata(&self) -> ModifierInspectorIterator<'_> {
849 match &self.kind {
850 ModifierKind::Empty => ModifierInspectorIterator { inner: [].iter() },
851 ModifierKind::Single { inspector, .. } => ModifierInspectorIterator {
852 inner: inspector.iter(),
853 },
854 }
855 }
856
857 #[cfg(test)]
858 pub(crate) fn elements(&self) -> Vec<DynModifierElement> {
859 match &self.kind {
860 ModifierKind::Empty => Vec::new(),
861 ModifierKind::Single { elements, .. } => elements.as_ref().clone(),
862 }
863 }
864
865 pub(crate) fn inspector_metadata(&self) -> Vec<InspectorMetadata> {
866 match &self.kind {
867 ModifierKind::Empty => Vec::new(),
868 ModifierKind::Single { inspector, .. } => inspector.as_ref().clone(),
869 }
870 }
871
872 pub(crate) fn rehouse_for_live_compaction(&self) -> Self {
873 match &self.kind {
874 ModifierKind::Empty => Self::default(),
875 ModifierKind::Single {
876 elements,
877 inspector,
878 } => Self {
879 kind: ModifierKind::Single {
880 elements: Rc::new(elements.iter().cloned().collect()),
881 inspector: Rc::new(inspector.as_ref().clone()),
882 },
883 strict_fingerprint: self.strict_fingerprint,
884 structural_fingerprint: self.structural_fingerprint,
885 element_count: self.element_count,
886 },
887 }
888 }
889
890 pub fn total_padding(&self) -> f32 {
891 let padding = self.padding_values();
892 padding
893 .left
894 .max(padding.right)
895 .max(padding.top)
896 .max(padding.bottom)
897 }
898
899 pub fn explicit_size(&self) -> Option<Size> {
900 let props = self.layout_properties();
901 match (props.width, props.height) {
902 (DimensionConstraint::Points(width), DimensionConstraint::Points(height)) => {
903 Some(Size { width, height })
904 }
905 _ => None,
906 }
907 }
908
909 pub fn padding_values(&self) -> EdgeInsets {
910 self.resolved_modifiers().padding()
911 }
912
913 pub(crate) fn layout_properties(&self) -> LayoutProperties {
914 self.resolved_modifiers().layout_properties()
915 }
916
917 pub fn box_alignment(&self) -> Option<Alignment> {
918 self.layout_properties().box_alignment()
919 }
920
921 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
922 self.layout_properties().column_alignment()
923 }
924
925 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
926 self.layout_properties().row_alignment()
927 }
928
929 pub fn draw_commands(&self) -> Vec<DrawCommand> {
930 collect_slices_from_modifier(self).draw_commands().to_vec()
931 }
932
933 pub fn clips_to_bounds(&self) -> bool {
934 collect_slices_from_modifier(self).clip_to_bounds()
935 }
936
937 pub fn collect_inspector_records(&self) -> Vec<ModifierInspectorRecord> {
939 self.inspector_metadata()
940 .iter()
941 .map(|metadata| metadata.to_record())
942 .collect()
943 }
944
945 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
946 let mut handle = ModifierChainHandle::new();
947 let _ = handle.update(self);
948 handle.resolved_modifiers()
949 }
950
951 pub(crate) fn with_element<E>(element: E) -> Self
952 where
953 E: ModifierNodeElement,
954 {
955 let dyn_element = modifier_element(element);
956 Self::from_parts(vec![dyn_element])
957 }
958
959 pub(crate) fn from_parts(elements: Vec<DynModifierElement>) -> Self {
960 if elements.is_empty() {
961 Self::default()
962 } else {
963 let element_count = elements.len();
964 let fingerprints = single_fingerprints(elements.as_slice());
965 Self {
966 kind: ModifierKind::Single {
967 elements: Rc::new(elements),
968 inspector: Rc::new(Vec::new()),
969 },
970 strict_fingerprint: fingerprints.strict,
971 structural_fingerprint: fingerprints.structural,
972 element_count,
973 }
974 }
975 }
976
977 fn is_trivially_empty(&self) -> bool {
978 matches!(self.kind, ModifierKind::Empty)
979 }
980
981 fn single_parts(&self) -> Option<(&[DynModifierElement], &[InspectorMetadata])> {
982 match &self.kind {
983 ModifierKind::Empty => None,
984 ModifierKind::Single {
985 elements,
986 inspector,
987 } => Some((elements.as_slice(), inspector.as_slice())),
988 }
989 }
990
991 pub(crate) fn with_inspector_metadata(self, metadata: InspectorMetadata) -> Self {
992 if metadata.is_empty() {
993 return self;
994 }
995 match self.kind {
996 ModifierKind::Empty => self,
997 ModifierKind::Single {
998 elements,
999 inspector,
1000 } => {
1001 let mut new_inspector = inspector.as_ref().clone();
1002 new_inspector.push(metadata);
1003 Self {
1004 kind: ModifierKind::Single {
1005 elements,
1006 inspector: Rc::new(new_inspector),
1007 },
1008 strict_fingerprint: self.strict_fingerprint,
1009 structural_fingerprint: self.structural_fingerprint,
1010 element_count: self.element_count,
1011 }
1012 }
1013 }
1014 }
1015
1016 pub fn structural_eq(&self, other: &Self) -> bool {
1021 self.eq_internal(other, false)
1022 }
1023
1024 fn eq_internal(&self, other: &Self, consider_always_update: bool) -> bool {
1025 if self.element_count != other.element_count {
1026 return false;
1027 }
1028 if consider_always_update {
1029 if self.strict_fingerprint != other.strict_fingerprint {
1030 return false;
1031 }
1032 } else if self.structural_fingerprint != other.structural_fingerprint {
1033 return false;
1034 }
1035
1036 match (&self.kind, &other.kind) {
1037 (ModifierKind::Empty, ModifierKind::Empty) => true,
1038 (
1039 ModifierKind::Single {
1040 elements: e1,
1041 inspector: _,
1042 },
1043 ModifierKind::Single {
1044 elements: e2,
1045 inspector: _,
1046 },
1047 ) => {
1048 if Rc::ptr_eq(e1, e2) {
1049 return true;
1050 }
1051
1052 if e1.len() != e2.len() {
1053 return false;
1054 }
1055
1056 for (a, b) in e1.iter().zip(e2.iter()) {
1057 if !consider_always_update
1058 && a.element_type() == b.element_type()
1059 && a.capabilities() == NodeCapabilities::DRAW
1060 && b.capabilities() == NodeCapabilities::DRAW
1061 {
1062 continue;
1063 }
1064
1065 if consider_always_update && (a.requires_update() || b.requires_update()) {
1066 if !Rc::ptr_eq(a, b) {
1067 return false;
1068 }
1069 continue;
1070 }
1071
1072 if !a.equals_element(&**b) {
1073 return false;
1074 }
1075 }
1076
1077 true
1078 }
1079 _ => false,
1080 }
1081 }
1082}
1083
1084impl PartialEq for Modifier {
1085 fn eq(&self, other: &Self) -> bool {
1086 self.eq_internal(other, true)
1087 }
1088}
1089
1090impl Eq for Modifier {}
1091
1092impl fmt::Display for Modifier {
1093 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1094 match &self.kind {
1095 ModifierKind::Empty => write!(f, "Modifier.empty"),
1096 ModifierKind::Single { elements, .. } => {
1097 if elements.is_empty() {
1098 return write!(f, "Modifier.empty");
1099 }
1100 write!(f, "Modifier[")?;
1101 for (index, element) in elements.iter().enumerate() {
1102 if index > 0 {
1103 write!(f, ", ")?;
1104 }
1105 let name = element.inspector_name();
1106 let mut properties = Vec::new();
1107 element.record_inspector_properties(&mut |prop, value| {
1108 properties.push(format!("{prop}={value}"));
1109 });
1110 if properties.is_empty() {
1111 write!(f, "{name}")?;
1112 } else {
1113 write!(f, "{name}({})", properties.join(", "))?;
1114 }
1115 }
1116 write!(f, "]")
1117 }
1118 }
1119 }
1120}
1121
1122impl fmt::Debug for Modifier {
1123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124 fmt::Display::fmt(self, f)
1125 }
1126}
1127
1128#[derive(Clone, Copy, Debug, PartialEq)]
1129pub struct ResolvedBackground {
1130 color: Color,
1131 shape: Option<RoundedCornerShape>,
1132}
1133
1134impl ResolvedBackground {
1135 pub fn new(color: Color, shape: Option<RoundedCornerShape>) -> Self {
1136 Self { color, shape }
1137 }
1138
1139 pub fn color(&self) -> Color {
1140 self.color
1141 }
1142
1143 pub fn shape(&self) -> Option<RoundedCornerShape> {
1144 self.shape
1145 }
1146
1147 pub fn set_shape(&mut self, shape: Option<RoundedCornerShape>) {
1148 self.shape = shape;
1149 }
1150}
1151
1152#[derive(Clone, Copy, Debug, PartialEq, Default)]
1153pub struct ResolvedModifiers {
1154 padding: EdgeInsets,
1155 layout: LayoutProperties,
1156 offset: Point,
1157}
1158
1159impl ResolvedModifiers {
1160 pub fn padding(&self) -> EdgeInsets {
1161 self.padding
1162 }
1163
1164 pub fn layout_properties(&self) -> LayoutProperties {
1165 self.layout
1166 }
1167
1168 pub fn offset(&self) -> Point {
1169 self.offset
1170 }
1171
1172 pub(crate) fn set_padding(&mut self, padding: EdgeInsets) {
1173 self.padding = padding;
1174 }
1175
1176 pub(crate) fn set_layout_properties(&mut self, layout: LayoutProperties) {
1177 self.layout = layout;
1178 }
1179
1180 pub(crate) fn set_offset(&mut self, offset: Point) {
1181 self.offset = offset;
1182 }
1183}
1184
1185#[derive(Clone, Copy, Debug, Default, PartialEq)]
1186pub enum DimensionConstraint {
1187 #[default]
1188 Unspecified,
1189 Points(f32),
1190 Fraction(f32),
1191 Intrinsic(IntrinsicSize),
1192}
1193
1194#[derive(Clone, Copy, Debug, Default, PartialEq)]
1195pub struct LayoutWeight {
1196 pub weight: f32,
1197 pub fill: bool,
1198}
1199
1200#[derive(Clone, Copy, Debug, Default, PartialEq)]
1201pub struct LayoutProperties {
1202 padding: EdgeInsets,
1203 width: DimensionConstraint,
1204 height: DimensionConstraint,
1205 min_width: Option<f32>,
1206 min_height: Option<f32>,
1207 max_width: Option<f32>,
1208 max_height: Option<f32>,
1209 weight: Option<LayoutWeight>,
1210 box_alignment: Option<Alignment>,
1211 column_alignment: Option<HorizontalAlignment>,
1212 row_alignment: Option<VerticalAlignment>,
1213}
1214
1215impl LayoutProperties {
1216 pub fn padding(&self) -> EdgeInsets {
1217 self.padding
1218 }
1219
1220 pub fn width(&self) -> DimensionConstraint {
1221 self.width
1222 }
1223
1224 pub fn height(&self) -> DimensionConstraint {
1225 self.height
1226 }
1227
1228 pub fn min_width(&self) -> Option<f32> {
1229 self.min_width
1230 }
1231
1232 pub fn min_height(&self) -> Option<f32> {
1233 self.min_height
1234 }
1235
1236 pub fn max_width(&self) -> Option<f32> {
1237 self.max_width
1238 }
1239
1240 pub fn max_height(&self) -> Option<f32> {
1241 self.max_height
1242 }
1243
1244 pub fn weight(&self) -> Option<LayoutWeight> {
1245 self.weight
1246 }
1247
1248 pub fn box_alignment(&self) -> Option<Alignment> {
1249 self.box_alignment
1250 }
1251
1252 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
1253 self.column_alignment
1254 }
1255
1256 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
1257 self.row_alignment
1258 }
1259}
1260
1261#[cfg(test)]
1262#[path = "tests/modifier_tests.rs"]
1263mod tests;