cranpose_ui/modifier/
minimum_interactive.rs1use cranpose_foundation::{
5 Constraints, DelegatableNode, InvalidationKind, LayoutModifierNode, Measurable, ModifierNode,
6 ModifierNodeContext, ModifierNodeElement, NodeCapabilities, NodeState, Size,
7};
8use cranpose_ui_layout::LayoutModifierMeasureResult;
9
10use super::Modifier;
11
12pub const MINIMUM_INTERACTIVE_SIZE: f32 = 48.0;
15
16pub fn minimum_interactive_placement(
20 constraints: Constraints,
21 content: Size,
22) -> LayoutModifierMeasureResult {
23 let width = content.width.max(
24 MINIMUM_INTERACTIVE_SIZE
25 .max(constraints.min_width)
26 .min(constraints.max_width),
27 );
28 let height = content.height.max(
29 MINIMUM_INTERACTIVE_SIZE
30 .max(constraints.min_height)
31 .min(constraints.max_height),
32 );
33 LayoutModifierMeasureResult::new(
34 Size { width, height },
35 ((width - content.width) / 2.0).round(),
36 ((height - content.height) / 2.0).round(),
37 )
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
42pub struct MinimumInteractiveElement;
43
44pub struct MinimumInteractiveNode {
46 state: NodeState,
47}
48
49impl DelegatableNode for MinimumInteractiveNode {
50 fn node_state(&self) -> &NodeState {
51 &self.state
52 }
53}
54
55crate::modifier_nodes::impl_layout_modifier_node!(
56 MinimumInteractiveNode,
57 invalidate = InvalidationKind::Layout
58);
59
60impl LayoutModifierNode for MinimumInteractiveNode {
61 fn measure(
62 &self,
63 _context: &mut dyn ModifierNodeContext,
64 measurable: &dyn Measurable,
65 constraints: Constraints,
66 ) -> LayoutModifierMeasureResult {
67 let placeable = measurable.measure(constraints);
68 minimum_interactive_placement(
69 constraints,
70 Size {
71 width: placeable.width(),
72 height: placeable.height(),
73 },
74 )
75 }
76
77 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
78 measurable
79 .min_intrinsic_width(height)
80 .max(MINIMUM_INTERACTIVE_SIZE)
81 }
82
83 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
84 measurable
85 .max_intrinsic_width(height)
86 .max(MINIMUM_INTERACTIVE_SIZE)
87 }
88
89 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
90 measurable
91 .min_intrinsic_height(width)
92 .max(MINIMUM_INTERACTIVE_SIZE)
93 }
94
95 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
96 measurable
97 .max_intrinsic_height(width)
98 .max(MINIMUM_INTERACTIVE_SIZE)
99 }
100}
101
102impl ModifierNodeElement for MinimumInteractiveElement {
103 type Node = MinimumInteractiveNode;
104
105 fn create(&self) -> Self::Node {
106 MinimumInteractiveNode {
107 state: NodeState::new(),
108 }
109 }
110
111 fn update(&self, _node: &mut Self::Node) {}
112
113 fn capabilities(&self) -> NodeCapabilities {
114 NodeCapabilities::LAYOUT
115 }
116}
117
118impl Modifier {
119 pub fn minimum_interactive_component_size(self) -> Self {
125 self.then(Self::with_element(MinimumInteractiveElement))
126 }
127}
128
129#[cfg(test)]
130#[path = "tests/minimum_interactive_tests.rs"]
131mod tests;