1#![allow(non_snake_case)]
9
10use std::fmt;
11use std::rc::Rc;
12
13mod alignment;
14mod background;
15mod blur;
16mod chain;
17mod clickable;
18mod draw_cache;
19mod fill;
20mod focus;
21mod graphics_layer;
22mod local;
23mod offset;
24mod padding;
25mod pointer_input;
26mod scroll;
27mod semantics;
28mod shadow;
29mod size;
30mod slices;
31mod weight;
32
33pub use crate::draw::{DrawCacheBuilder, DrawCommand};
34#[allow(unused_imports)]
35pub use chain::{ModifierChainHandle, ModifierChainInspectorNode, ModifierLocalsHandle};
36pub use cranpose_foundation::{
37 modifier_element, AnyModifierElement, DynModifierElement, FocusState, PointerEvent,
38 PointerEventKind, SemanticsConfiguration,
39};
40use cranpose_foundation::{ModifierNodeElement, NodeCapabilities};
41#[allow(unused_imports)]
42pub use cranpose_ui_graphics::{
43 BlendMode, BlurredEdgeTreatment, Brush, Color, ColorFilter, CompositingStrategy, CornerRadii,
44 CutDirection, Dp, DpOffset, EdgeInsets, GradientCutMaskSpec, GradientFadeMaskSpec,
45 GraphicsLayer, LayerShape, Point, Rect, RenderEffect, RoundedCornerShape, RuntimeShader,
46 Shadow, ShadowScope, Size, TransformOrigin,
47};
48use cranpose_ui_layout::{Alignment, HorizontalAlignment, IntrinsicSize, VerticalAlignment};
49#[allow(unused_imports)]
50pub use focus::{FocusDirection, FocusRequester};
51pub(crate) use local::{
52 ModifierLocalAncestorResolver, ModifierLocalSource, ModifierLocalToken, ResolvedModifierLocal,
53};
54#[allow(unused_imports)]
55pub use local::{ModifierLocalKey, ModifierLocalReadScope};
56#[allow(unused_imports)]
57pub use pointer_input::{AwaitPointerEventScope, PointerInputScope};
58pub use semantics::{collect_semantics_from_chain, collect_semantics_from_modifier};
59pub use slices::{
60 collect_modifier_slices, collect_modifier_slices_into, collect_slices_from_modifier,
61 ModifierNodeSlices,
62};
63#[cfg(feature = "test-helpers")]
65pub use scroll::{last_fling_velocity, reset_last_fling_velocity};
66
67use crate::modifier_nodes::ClipToBoundsElement;
68use focus::{FocusRequesterElement, FocusTargetElement};
69use local::{ModifierLocalConsumerElement, ModifierLocalProviderElement};
70use semantics::SemanticsElement;
71
72#[derive(Clone, Debug, Default)]
74pub struct InspectorInfo {
75 properties: Vec<InspectorProperty>,
76}
77
78impl InspectorInfo {
79 pub fn new() -> Self {
80 Self::default()
81 }
82
83 pub fn add_property<V: Into<String>>(&mut self, name: &'static str, value: V) {
84 self.properties.push(InspectorProperty {
85 name,
86 value: value.into(),
87 });
88 }
89
90 pub fn properties(&self) -> &[InspectorProperty] {
91 &self.properties
92 }
93
94 pub fn is_empty(&self) -> bool {
95 self.properties.is_empty()
96 }
97
98 pub fn add_dimension(&mut self, name: &'static str, constraint: DimensionConstraint) {
99 self.add_property(name, describe_dimension(constraint));
100 }
101
102 pub fn add_offset_components(
103 &mut self,
104 x_name: &'static str,
105 y_name: &'static str,
106 offset: Point,
107 ) {
108 self.add_property(x_name, offset.x.to_string());
109 self.add_property(y_name, offset.y.to_string());
110 }
111
112 pub fn add_alignment<A>(&mut self, name: &'static str, alignment: A)
113 where
114 A: fmt::Debug,
115 {
116 self.add_property(name, format!("{alignment:?}"));
117 }
118
119 #[allow(dead_code)] pub fn debug_properties(&self) -> Vec<(&'static str, String)> {
121 self.properties
122 .iter()
123 .map(|property| (property.name, property.value.clone()))
124 .collect()
125 }
126
127 #[allow(dead_code)] pub fn describe(&self) -> String {
129 self.properties
130 .iter()
131 .map(|property| format!("{}={}", property.name, property.value))
132 .collect::<Vec<_>>()
133 .join(", ")
134 }
135}
136
137#[derive(Clone, Debug, PartialEq)]
139pub struct InspectorProperty {
140 pub name: &'static str,
141 pub value: String,
142}
143
144#[derive(Clone, Debug, PartialEq)]
146pub struct ModifierInspectorRecord {
147 pub name: &'static str,
148 pub properties: Vec<InspectorProperty>,
149}
150
151#[derive(Clone, Debug)]
153pub(crate) struct InspectorMetadata {
154 name: &'static str,
155 info: InspectorInfo,
156}
157
158impl InspectorMetadata {
159 pub(crate) fn new<F>(name: &'static str, recorder: F) -> Self
160 where
161 F: FnOnce(&mut InspectorInfo),
162 {
163 let mut info = InspectorInfo::new();
164 recorder(&mut info);
165 Self { name, info }
166 }
167
168 fn is_empty(&self) -> bool {
169 self.info.is_empty()
170 }
171
172 fn to_record(&self) -> ModifierInspectorRecord {
173 ModifierInspectorRecord {
174 name: self.name,
175 properties: self.info.properties().to_vec(),
176 }
177 }
178}
179
180fn describe_dimension(constraint: DimensionConstraint) -> String {
181 match constraint {
182 DimensionConstraint::Unspecified => "unspecified".to_string(),
183 DimensionConstraint::Points(value) => value.to_string(),
184 DimensionConstraint::Fraction(value) => format!("fraction({value})"),
185 DimensionConstraint::Intrinsic(size) => format!("intrinsic({size:?})"),
186 }
187}
188
189pub(crate) fn inspector_metadata<F>(name: &'static str, recorder: F) -> InspectorMetadata
190where
191 F: FnOnce(&mut InspectorInfo),
192{
193 InspectorMetadata::new(name, recorder)
194}
195
196#[derive(Clone)]
200enum ModifierKind {
201 Empty,
203 Single {
205 elements: Rc<Vec<DynModifierElement>>,
206 inspector: Rc<Vec<InspectorMetadata>>,
207 },
208 Combined {
210 outer: Rc<Modifier>,
211 inner: Rc<Modifier>,
212 },
213}
214
215pub struct ModifierElementIterator<'a> {
220 stack: Vec<&'a Modifier>,
222 current_elements: Option<(&'a [DynModifierElement], usize)>,
224}
225
226impl<'a> ModifierElementIterator<'a> {
227 fn new(modifier: &'a Modifier) -> Self {
228 let mut iter = Self {
229 stack: Vec::new(),
230 current_elements: None,
231 };
232 iter.push_modifier(modifier);
233 iter
234 }
235
236 fn push_modifier(&mut self, modifier: &'a Modifier) {
237 match &modifier.kind {
238 ModifierKind::Empty => {}
239 ModifierKind::Single { elements, .. } => {
240 if !elements.is_empty() {
241 self.current_elements = Some((elements.as_slice(), 0));
242 }
243 }
244 ModifierKind::Combined { outer, inner } => {
245 self.stack.push(inner.as_ref());
247 self.push_modifier(outer.as_ref());
248 }
249 }
250 }
251}
252
253impl<'a> Iterator for ModifierElementIterator<'a> {
254 type Item = &'a DynModifierElement;
255
256 fn next(&mut self) -> Option<Self::Item> {
257 loop {
258 if let Some((elements, index)) = &mut self.current_elements {
260 if *index < elements.len() {
261 let element = &elements[*index];
262 *index += 1;
263 return Some(element);
264 }
265 self.current_elements = None;
266 }
267
268 let next_modifier = self.stack.pop()?;
270 self.push_modifier(next_modifier);
271 }
272 }
273}
274
275pub(crate) struct ModifierInspectorIterator<'a> {
277 stack: Vec<&'a Modifier>,
278 current_inspector: Option<(&'a [InspectorMetadata], usize)>,
279}
280
281impl<'a> ModifierInspectorIterator<'a> {
282 fn new(modifier: &'a Modifier) -> Self {
283 let mut iter = Self {
284 stack: Vec::new(),
285 current_inspector: None,
286 };
287 iter.push_modifier(modifier);
288 iter
289 }
290
291 fn push_modifier(&mut self, modifier: &'a Modifier) {
292 match &modifier.kind {
293 ModifierKind::Empty => {}
294 ModifierKind::Single { inspector, .. } => {
295 if !inspector.is_empty() {
296 self.current_inspector = Some((inspector.as_slice(), 0));
297 }
298 }
299 ModifierKind::Combined { outer, inner } => {
300 self.stack.push(inner.as_ref());
302 self.push_modifier(outer.as_ref());
303 }
304 }
305 }
306}
307
308impl<'a> Iterator for ModifierInspectorIterator<'a> {
309 type Item = &'a InspectorMetadata;
310
311 fn next(&mut self) -> Option<Self::Item> {
312 loop {
313 if let Some((inspector, index)) = &mut self.current_inspector {
314 if *index < inspector.len() {
315 let metadata = &inspector[*index];
316 *index += 1;
317 return Some(metadata);
318 }
319 self.current_inspector = None;
320 }
321
322 let next_modifier = self.stack.pop()?;
323 self.push_modifier(next_modifier);
324 }
325 }
326}
327
328#[derive(Clone)]
346pub struct Modifier {
347 kind: ModifierKind,
348}
349
350impl Default for Modifier {
351 fn default() -> Self {
352 Self {
353 kind: ModifierKind::Empty,
354 }
355 }
356}
357
358impl Modifier {
359 pub fn empty() -> Self {
360 Self::default()
361 }
362
363 pub fn clip_to_bounds(self) -> Self {
367 let modifier = Self::with_element(ClipToBoundsElement::new()).with_inspector_metadata(
368 inspector_metadata("clipToBounds", |info| {
369 info.add_property("clipToBounds", "true");
370 }),
371 );
372 self.then(modifier)
373 }
374
375 pub fn modifier_local_provider<T, F>(self, key: ModifierLocalKey<T>, value: F) -> Self
376 where
377 T: 'static,
378 F: Fn() -> T + 'static,
379 {
380 let element = ModifierLocalProviderElement::new(key, value);
381 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
382 self.then(modifier)
383 }
384
385 pub fn modifier_local_consumer<F>(self, consumer: F) -> Self
386 where
387 F: for<'scope> Fn(&mut ModifierLocalReadScope<'scope>) + 'static,
388 {
389 let element = ModifierLocalConsumerElement::new(consumer);
390 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
391 self.then(modifier)
392 }
393
394 pub fn semantics<F>(self, recorder: F) -> Self
395 where
396 F: Fn(&mut SemanticsConfiguration) + 'static,
397 {
398 let mut preview = SemanticsConfiguration::default();
399 recorder(&mut preview);
400 let description = preview.content_description.clone();
401 let is_button = preview.is_button;
402 let is_clickable = preview.is_clickable;
403 let metadata = inspector_metadata("semantics", move |info| {
404 if let Some(desc) = &description {
405 info.add_property("contentDescription", desc.clone());
406 }
407 if is_button {
408 info.add_property("isButton", "true");
409 }
410 if is_clickable {
411 info.add_property("isClickable", "true");
412 }
413 });
414 let element = SemanticsElement::new(recorder);
415 let modifier =
416 Modifier::from_parts(vec![modifier_element(element)]).with_inspector_metadata(metadata);
417 self.then(modifier)
418 }
419
420 pub fn focus_target(self) -> Self {
426 let element = FocusTargetElement::new();
427 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
428 self.then(modifier)
429 }
430
431 pub fn on_focus_changed<F>(self, callback: F) -> Self
436 where
437 F: Fn(FocusState) + 'static,
438 {
439 let element = FocusTargetElement::with_callback(callback);
440 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
441 self.then(modifier)
442 }
443
444 pub fn focus_requester(self, requester: &FocusRequester) -> Self {
449 let element = FocusRequesterElement::new(requester.id());
450 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
451 self.then(modifier)
452 }
453
454 pub fn debug_chain(self, tag: &'static str) -> Self {
472 use cranpose_foundation::{ModifierNode, ModifierNodeContext, NodeCapabilities, NodeState};
473
474 #[derive(Clone)]
475 struct DebugChainElement {
476 tag: &'static str,
477 }
478
479 impl fmt::Debug for DebugChainElement {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 f.debug_struct("DebugChainElement")
482 .field("tag", &self.tag)
483 .finish()
484 }
485 }
486
487 impl PartialEq for DebugChainElement {
488 fn eq(&self, other: &Self) -> bool {
489 self.tag == other.tag
490 }
491 }
492
493 impl Eq for DebugChainElement {}
494
495 impl std::hash::Hash for DebugChainElement {
496 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
497 self.tag.hash(state);
498 }
499 }
500
501 impl ModifierNodeElement for DebugChainElement {
502 type Node = DebugChainNode;
503
504 fn create(&self) -> Self::Node {
505 DebugChainNode::new(self.tag)
506 }
507
508 fn update(&self, node: &mut Self::Node) {
509 node.tag = self.tag;
510 }
511
512 fn capabilities(&self) -> NodeCapabilities {
513 NodeCapabilities::empty()
514 }
515 }
516
517 struct DebugChainNode {
518 tag: &'static str,
519 state: NodeState,
520 }
521
522 impl DebugChainNode {
523 fn new(tag: &'static str) -> Self {
524 Self {
525 tag,
526 state: NodeState::new(),
527 }
528 }
529 }
530
531 impl ModifierNode for DebugChainNode {
532 fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {
533 eprintln!("[debug_chain:{}] Modifier chain attached", self.tag);
534 }
535
536 fn on_detach(&mut self) {
537 eprintln!("[debug_chain:{}] Modifier chain detached", self.tag);
538 }
539
540 fn on_reset(&mut self) {
541 eprintln!("[debug_chain:{}] Modifier chain reset", self.tag);
542 }
543 }
544
545 impl cranpose_foundation::DelegatableNode for DebugChainNode {
546 fn node_state(&self) -> &NodeState {
547 &self.state
548 }
549 }
550
551 let element = DebugChainElement { tag };
552 let modifier = Modifier::from_parts(vec![modifier_element(element)]);
553 self.then(modifier)
554 .with_inspector_metadata(inspector_metadata("debugChain", move |info| {
555 info.add_property("tag", tag);
556 }))
557 }
558
559 pub fn then(&self, next: Modifier) -> Modifier {
567 if self.is_trivially_empty() {
568 return next;
569 }
570 if next.is_trivially_empty() {
571 return self.clone();
572 }
573 Modifier {
574 kind: ModifierKind::Combined {
575 outer: Rc::new(self.clone()),
576 inner: Rc::new(next),
577 },
578 }
579 }
580
581 pub(crate) fn iter_elements(&self) -> ModifierElementIterator<'_> {
587 ModifierElementIterator::new(self)
588 }
589
590 pub(crate) fn iter_inspector_metadata(&self) -> ModifierInspectorIterator<'_> {
591 ModifierInspectorIterator::new(self)
592 }
593
594 pub(crate) fn elements(&self) -> Vec<DynModifierElement> {
599 match &self.kind {
600 ModifierKind::Empty => Vec::new(),
601 ModifierKind::Single { elements, .. } => elements.as_ref().clone(),
602 ModifierKind::Combined { outer, inner } => {
603 let mut result = outer.elements();
604 result.extend(inner.elements());
605 result
606 }
607 }
608 }
609
610 pub(crate) fn inspector_metadata(&self) -> Vec<InspectorMetadata> {
614 match &self.kind {
615 ModifierKind::Empty => Vec::new(),
616 ModifierKind::Single { inspector, .. } => inspector.as_ref().clone(),
617 ModifierKind::Combined { outer, inner } => {
618 let mut result = outer.inspector_metadata();
619 result.extend(inner.inspector_metadata());
620 result
621 }
622 }
623 }
624
625 pub fn total_padding(&self) -> f32 {
626 let padding = self.padding_values();
627 padding
628 .left
629 .max(padding.right)
630 .max(padding.top)
631 .max(padding.bottom)
632 }
633
634 pub fn explicit_size(&self) -> Option<Size> {
635 let props = self.layout_properties();
636 match (props.width, props.height) {
637 (DimensionConstraint::Points(width), DimensionConstraint::Points(height)) => {
638 Some(Size { width, height })
639 }
640 _ => None,
641 }
642 }
643
644 pub fn padding_values(&self) -> EdgeInsets {
645 self.resolved_modifiers().padding()
646 }
647
648 pub(crate) fn layout_properties(&self) -> LayoutProperties {
649 self.resolved_modifiers().layout_properties()
650 }
651
652 pub fn box_alignment(&self) -> Option<Alignment> {
653 self.layout_properties().box_alignment()
654 }
655
656 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
657 self.layout_properties().column_alignment()
658 }
659
660 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
661 self.layout_properties().row_alignment()
662 }
663
664 pub fn draw_commands(&self) -> Vec<DrawCommand> {
665 collect_slices_from_modifier(self).draw_commands().to_vec()
666 }
667
668 pub fn clips_to_bounds(&self) -> bool {
669 collect_slices_from_modifier(self).clip_to_bounds()
670 }
671
672 pub fn collect_inspector_records(&self) -> Vec<ModifierInspectorRecord> {
674 self.inspector_metadata()
675 .iter()
676 .map(|metadata| metadata.to_record())
677 .collect()
678 }
679
680 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
681 let mut handle = ModifierChainHandle::new();
682 let _ = handle.update(self);
683 handle.resolved_modifiers()
684 }
685
686 fn with_element<E>(element: E) -> Self
687 where
688 E: ModifierNodeElement,
689 {
690 let dyn_element = modifier_element(element);
691 Self::from_parts(vec![dyn_element])
692 }
693
694 pub(crate) fn from_parts(elements: Vec<DynModifierElement>) -> Self {
695 if elements.is_empty() {
696 Self {
697 kind: ModifierKind::Empty,
698 }
699 } else {
700 Self {
701 kind: ModifierKind::Single {
702 elements: Rc::new(elements),
703 inspector: Rc::new(Vec::new()),
704 },
705 }
706 }
707 }
708
709 fn is_trivially_empty(&self) -> bool {
710 matches!(self.kind, ModifierKind::Empty)
711 }
712
713 pub(crate) fn with_inspector_metadata(self, metadata: InspectorMetadata) -> Self {
714 if metadata.is_empty() {
715 return self;
716 }
717 match self.kind {
718 ModifierKind::Empty => self,
719 ModifierKind::Single {
720 elements,
721 inspector,
722 } => {
723 let mut new_inspector = inspector.as_ref().clone();
724 new_inspector.push(metadata);
725 Self {
726 kind: ModifierKind::Single {
727 elements,
728 inspector: Rc::new(new_inspector),
729 },
730 }
731 }
732 ModifierKind::Combined { .. } => {
733 panic!("Cannot add inspector metadata to a combined modifier")
736 }
737 }
738 }
739
740 pub fn structural_eq(&self, other: &Self) -> bool {
745 self.eq_internal(other, false)
746 }
747
748 fn eq_internal(&self, other: &Self, consider_always_update: bool) -> bool {
749 match (&self.kind, &other.kind) {
750 (ModifierKind::Empty, ModifierKind::Empty) => true,
751 (
752 ModifierKind::Single {
753 elements: e1,
754 inspector: _,
755 },
756 ModifierKind::Single {
757 elements: e2,
758 inspector: _,
759 },
760 ) => {
761 if Rc::ptr_eq(e1, e2) {
762 return true;
763 }
764
765 if e1.len() != e2.len() {
766 return false;
767 }
768
769 for (a, b) in e1.iter().zip(e2.iter()) {
770 if !consider_always_update
774 && a.element_type() == b.element_type()
775 && a.capabilities() == NodeCapabilities::DRAW
776 && b.capabilities() == NodeCapabilities::DRAW
777 {
778 continue;
779 }
780
781 if consider_always_update && (a.requires_update() || b.requires_update()) {
782 if !Rc::ptr_eq(a, b) {
783 return false;
784 }
785 continue;
786 }
787
788 if !a.equals_element(&**b) {
789 return false;
790 }
791 }
792
793 true
794 }
795 (
796 ModifierKind::Combined {
797 outer: o1,
798 inner: i1,
799 },
800 ModifierKind::Combined {
801 outer: o2,
802 inner: i2,
803 },
804 ) => {
805 if Rc::ptr_eq(o1, o2) && Rc::ptr_eq(i1, i2) {
806 return true;
807 }
808 o1.as_ref().eq_internal(o2.as_ref(), consider_always_update)
809 && i1.as_ref().eq_internal(i2.as_ref(), consider_always_update)
810 }
811 _ => false,
812 }
813 }
814}
815
816impl PartialEq for Modifier {
817 fn eq(&self, other: &Self) -> bool {
818 self.eq_internal(other, true)
819 }
820}
821
822impl Eq for Modifier {}
823
824impl fmt::Display for Modifier {
825 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
826 match &self.kind {
827 ModifierKind::Empty => write!(f, "Modifier.empty"),
828 ModifierKind::Single { elements, .. } => {
829 if elements.is_empty() {
830 return write!(f, "Modifier.empty");
831 }
832 write!(f, "Modifier[")?;
833 for (index, element) in elements.iter().enumerate() {
834 if index > 0 {
835 write!(f, ", ")?;
836 }
837 let name = element.inspector_name();
838 let mut properties = Vec::new();
839 element.record_inspector_properties(&mut |prop, value| {
840 properties.push(format!("{prop}={value}"));
841 });
842 if properties.is_empty() {
843 write!(f, "{name}")?;
844 } else {
845 write!(f, "{name}({})", properties.join(", "))?;
846 }
847 }
848 write!(f, "]")
849 }
850 ModifierKind::Combined { outer: _, inner: _ } => {
851 write!(f, "[")?;
854 let elements = self.elements();
855 for (index, element) in elements.iter().enumerate() {
856 if index > 0 {
857 write!(f, ", ")?;
858 }
859 let name = element.inspector_name();
860 let mut properties = Vec::new();
861 element.record_inspector_properties(&mut |prop, value| {
862 properties.push(format!("{prop}={value}"));
863 });
864 if properties.is_empty() {
865 write!(f, "{name}")?;
866 } else {
867 write!(f, "{name}({})", properties.join(", "))?;
868 }
869 }
870 write!(f, "]")
871 }
872 }
873 }
874}
875
876impl fmt::Debug for Modifier {
877 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
878 fmt::Display::fmt(self, f)
879 }
880}
881
882#[derive(Clone, Copy, Debug, PartialEq)]
883pub struct ResolvedBackground {
884 color: Color,
885 shape: Option<RoundedCornerShape>,
886}
887
888impl ResolvedBackground {
889 pub fn new(color: Color, shape: Option<RoundedCornerShape>) -> Self {
890 Self { color, shape }
891 }
892
893 pub fn color(&self) -> Color {
894 self.color
895 }
896
897 pub fn shape(&self) -> Option<RoundedCornerShape> {
898 self.shape
899 }
900
901 pub fn set_shape(&mut self, shape: Option<RoundedCornerShape>) {
902 self.shape = shape;
903 }
904}
905
906#[derive(Clone, Copy, Debug, PartialEq, Default)]
907pub struct ResolvedModifiers {
908 padding: EdgeInsets,
909 layout: LayoutProperties,
910 offset: Point,
911}
912
913impl ResolvedModifiers {
914 pub fn padding(&self) -> EdgeInsets {
915 self.padding
916 }
917
918 pub fn layout_properties(&self) -> LayoutProperties {
919 self.layout
920 }
921
922 pub fn offset(&self) -> Point {
923 self.offset
924 }
925
926 pub(crate) fn set_padding(&mut self, padding: EdgeInsets) {
927 self.padding = padding;
928 }
929
930 pub(crate) fn set_layout_properties(&mut self, layout: LayoutProperties) {
931 self.layout = layout;
932 }
933
934 pub(crate) fn set_offset(&mut self, offset: Point) {
935 self.offset = offset;
936 }
937}
938
939#[derive(Clone, Copy, Debug, Default, PartialEq)]
940pub enum DimensionConstraint {
941 #[default]
942 Unspecified,
943 Points(f32),
944 Fraction(f32),
945 Intrinsic(IntrinsicSize),
946}
947
948#[derive(Clone, Copy, Debug, Default, PartialEq)]
949pub struct LayoutWeight {
950 pub weight: f32,
951 pub fill: bool,
952}
953
954#[derive(Clone, Copy, Debug, Default, PartialEq)]
955pub struct LayoutProperties {
956 padding: EdgeInsets,
957 width: DimensionConstraint,
958 height: DimensionConstraint,
959 min_width: Option<f32>,
960 min_height: Option<f32>,
961 max_width: Option<f32>,
962 max_height: Option<f32>,
963 weight: Option<LayoutWeight>,
964 box_alignment: Option<Alignment>,
965 column_alignment: Option<HorizontalAlignment>,
966 row_alignment: Option<VerticalAlignment>,
967}
968
969impl LayoutProperties {
970 pub fn padding(&self) -> EdgeInsets {
971 self.padding
972 }
973
974 pub fn width(&self) -> DimensionConstraint {
975 self.width
976 }
977
978 pub fn height(&self) -> DimensionConstraint {
979 self.height
980 }
981
982 pub fn min_width(&self) -> Option<f32> {
983 self.min_width
984 }
985
986 pub fn min_height(&self) -> Option<f32> {
987 self.min_height
988 }
989
990 pub fn max_width(&self) -> Option<f32> {
991 self.max_width
992 }
993
994 pub fn max_height(&self) -> Option<f32> {
995 self.max_height
996 }
997
998 pub fn weight(&self) -> Option<LayoutWeight> {
999 self.weight
1000 }
1001
1002 pub fn box_alignment(&self) -> Option<Alignment> {
1003 self.box_alignment
1004 }
1005
1006 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
1007 self.column_alignment
1008 }
1009
1010 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
1011 self.row_alignment
1012 }
1013}
1014
1015#[cfg(test)]
1016#[path = "tests/modifier_tests.rs"]
1017mod tests;