1use cranpose_foundation::{
64 Constraints, DelegatableNode, DrawModifierNode, DrawScope, LayoutModifierNode, Measurable,
65 MeasurementProxy, ModifierNode, ModifierNodeContext, ModifierNodeElement, NodeCapabilities,
66 NodeState, PointerEvent, PointerEventKind, PointerInputNode, Size,
67};
68use cranpose_ui_layout::{Alignment, HorizontalAlignment, IntrinsicSize, VerticalAlignment};
69
70use std::hash::{Hash, Hasher};
71use std::rc::Rc;
72
73use crate::draw::DrawCommand;
74use crate::modifier::{Color, EdgeInsets, GraphicsLayer, LayoutWeight, Point, RoundedCornerShape};
75
76fn hash_f32_value<H: Hasher>(state: &mut H, value: f32) {
77 state.write_u32(value.to_bits());
78}
79
80fn hash_option_f32<H: Hasher>(state: &mut H, value: Option<f32>) {
81 match value {
82 Some(v) => {
83 state.write_u8(1);
84 hash_f32_value(state, v);
85 }
86 None => state.write_u8(0),
87 }
88}
89
90fn hash_graphics_layer<H: Hasher>(state: &mut H, layer: GraphicsLayer) {
91 hash_f32_value(state, layer.alpha);
92 hash_f32_value(state, layer.scale);
93 hash_f32_value(state, layer.translation_x);
94 hash_f32_value(state, layer.translation_y);
95}
96
97fn hash_horizontal_alignment<H: Hasher>(state: &mut H, alignment: HorizontalAlignment) {
98 let tag = match alignment {
99 HorizontalAlignment::Start => 0,
100 HorizontalAlignment::CenterHorizontally => 1,
101 HorizontalAlignment::End => 2,
102 };
103 state.write_u8(tag);
104}
105
106fn hash_vertical_alignment<H: Hasher>(state: &mut H, alignment: VerticalAlignment) {
107 let tag = match alignment {
108 VerticalAlignment::Top => 0,
109 VerticalAlignment::CenterVertically => 1,
110 VerticalAlignment::Bottom => 2,
111 };
112 state.write_u8(tag);
113}
114
115fn hash_alignment<H: Hasher>(state: &mut H, alignment: Alignment) {
116 hash_horizontal_alignment(state, alignment.horizontal);
117 hash_vertical_alignment(state, alignment.vertical);
118}
119
120#[derive(Debug)]
126pub struct PaddingNode {
127 padding: EdgeInsets,
128 state: NodeState,
129}
130
131impl PaddingNode {
132 pub fn new(padding: EdgeInsets) -> Self {
133 Self {
134 padding,
135 state: NodeState::new(),
136 }
137 }
138
139 pub fn padding(&self) -> EdgeInsets {
140 self.padding
141 }
142}
143
144impl DelegatableNode for PaddingNode {
145 fn node_state(&self) -> &NodeState {
146 &self.state
147 }
148}
149
150impl ModifierNode for PaddingNode {
151 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
152 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
153 }
154
155 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
156 Some(self)
157 }
158
159 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
160 Some(self)
161 }
162}
163
164impl LayoutModifierNode for PaddingNode {
165 fn measure(
166 &self,
167 _context: &mut dyn ModifierNodeContext,
168 measurable: &dyn Measurable,
169 constraints: Constraints,
170 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
171 let horizontal_padding = self.padding.horizontal_sum();
173 let vertical_padding = self.padding.vertical_sum();
174
175 let inner_constraints = Constraints {
177 min_width: (constraints.min_width - horizontal_padding).max(0.0),
178 max_width: (constraints.max_width - horizontal_padding).max(0.0),
179 min_height: (constraints.min_height - vertical_padding).max(0.0),
180 max_height: (constraints.max_height - vertical_padding).max(0.0),
181 };
182
183 let inner_placeable = measurable.measure(inner_constraints);
185 let inner_width = inner_placeable.width();
186 let inner_height = inner_placeable.height();
187
188 let (width, height) = constraints.constrain(
189 inner_width + horizontal_padding,
190 inner_height + vertical_padding,
191 );
192
193 cranpose_ui_layout::LayoutModifierMeasureResult::new(
195 Size { width, height },
196 self.padding.left, self.padding.top, )
199 }
200
201 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
202 let vertical_padding = self.padding.vertical_sum();
203 let inner_height = (height - vertical_padding).max(0.0);
204 let inner_width = measurable.min_intrinsic_width(inner_height);
205 inner_width + self.padding.horizontal_sum()
206 }
207
208 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
209 let vertical_padding = self.padding.vertical_sum();
210 let inner_height = (height - vertical_padding).max(0.0);
211 let inner_width = measurable.max_intrinsic_width(inner_height);
212 inner_width + self.padding.horizontal_sum()
213 }
214
215 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
216 let horizontal_padding = self.padding.horizontal_sum();
217 let inner_width = (width - horizontal_padding).max(0.0);
218 let inner_height = measurable.min_intrinsic_height(inner_width);
219 inner_height + self.padding.vertical_sum()
220 }
221
222 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
223 let horizontal_padding = self.padding.horizontal_sum();
224 let inner_width = (width - horizontal_padding).max(0.0);
225 let inner_height = measurable.max_intrinsic_height(inner_width);
226 inner_height + self.padding.vertical_sum()
227 }
228
229 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
230 Some(Box::new(PaddingMeasurementProxy {
231 padding: self.padding,
232 }))
233 }
234}
235
236struct PaddingMeasurementProxy {
242 padding: EdgeInsets,
243}
244
245impl MeasurementProxy for PaddingMeasurementProxy {
246 fn measure_proxy(
247 &self,
248 _context: &mut dyn ModifierNodeContext,
249 wrapped: &dyn Measurable,
250 constraints: Constraints,
251 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
252 let horizontal_padding = self.padding.horizontal_sum();
254 let vertical_padding = self.padding.vertical_sum();
255
256 let inner_constraints = Constraints {
258 min_width: (constraints.min_width - horizontal_padding).max(0.0),
259 max_width: (constraints.max_width - horizontal_padding).max(0.0),
260 min_height: (constraints.min_height - vertical_padding).max(0.0),
261 max_height: (constraints.max_height - vertical_padding).max(0.0),
262 };
263
264 let inner_placeable = wrapped.measure(inner_constraints);
266 let inner_width = inner_placeable.width();
267 let inner_height = inner_placeable.height();
268
269 let (width, height) = constraints.constrain(
270 inner_width + horizontal_padding,
271 inner_height + vertical_padding,
272 );
273
274 cranpose_ui_layout::LayoutModifierMeasureResult::new(
276 Size { width, height },
277 self.padding.left, self.padding.top, )
280 }
281
282 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
283 let vertical_padding = self.padding.vertical_sum();
284 let inner_height = (height - vertical_padding).max(0.0);
285 let inner_width = wrapped.min_intrinsic_width(inner_height);
286 inner_width + self.padding.horizontal_sum()
287 }
288
289 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
290 let vertical_padding = self.padding.vertical_sum();
291 let inner_height = (height - vertical_padding).max(0.0);
292 let inner_width = wrapped.max_intrinsic_width(inner_height);
293 inner_width + self.padding.horizontal_sum()
294 }
295
296 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
297 let horizontal_padding = self.padding.horizontal_sum();
298 let inner_width = (width - horizontal_padding).max(0.0);
299 let inner_height = wrapped.min_intrinsic_height(inner_width);
300 inner_height + self.padding.vertical_sum()
301 }
302
303 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
304 let horizontal_padding = self.padding.horizontal_sum();
305 let inner_width = (width - horizontal_padding).max(0.0);
306 let inner_height = wrapped.max_intrinsic_height(inner_width);
307 inner_height + self.padding.vertical_sum()
308 }
309}
310
311#[derive(Debug, Clone, PartialEq)]
313pub struct PaddingElement {
314 padding: EdgeInsets,
315}
316
317impl PaddingElement {
318 pub fn new(padding: EdgeInsets) -> Self {
319 Self { padding }
320 }
321}
322
323impl Hash for PaddingElement {
324 fn hash<H: Hasher>(&self, state: &mut H) {
325 hash_f32_value(state, self.padding.left);
326 hash_f32_value(state, self.padding.top);
327 hash_f32_value(state, self.padding.right);
328 hash_f32_value(state, self.padding.bottom);
329 }
330}
331
332impl ModifierNodeElement for PaddingElement {
333 type Node = PaddingNode;
334
335 fn create(&self) -> Self::Node {
336 PaddingNode::new(self.padding)
337 }
338
339 fn update(&self, node: &mut Self::Node) {
340 if node.padding != self.padding {
341 node.padding = self.padding;
342 }
344 }
345
346 fn capabilities(&self) -> NodeCapabilities {
347 NodeCapabilities::LAYOUT
348 }
349}
350
351#[derive(Debug)]
357pub struct BackgroundNode {
358 color: Color,
359 shape: Option<RoundedCornerShape>,
360 state: NodeState,
361}
362
363impl BackgroundNode {
364 pub fn new(color: Color) -> Self {
365 Self {
366 color,
367 shape: None,
368 state: NodeState::new(),
369 }
370 }
371
372 pub fn color(&self) -> Color {
373 self.color
374 }
375
376 pub fn shape(&self) -> Option<RoundedCornerShape> {
377 self.shape
378 }
379}
380
381impl DelegatableNode for BackgroundNode {
382 fn node_state(&self) -> &NodeState {
383 &self.state
384 }
385}
386
387impl ModifierNode for BackgroundNode {
388 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
389 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
390 }
391
392 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
393 Some(self)
394 }
395
396 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
397 Some(self)
398 }
399}
400
401impl DrawModifierNode for BackgroundNode {
402 fn draw(&self, _draw_scope: &mut dyn DrawScope) {
403 }
406}
407
408#[derive(Debug, Clone, PartialEq)]
410pub struct BackgroundElement {
411 color: Color,
412}
413
414impl BackgroundElement {
415 pub fn new(color: Color) -> Self {
416 Self { color }
417 }
418}
419
420impl Hash for BackgroundElement {
421 fn hash<H: Hasher>(&self, state: &mut H) {
422 hash_f32_value(state, self.color.0);
423 hash_f32_value(state, self.color.1);
424 hash_f32_value(state, self.color.2);
425 hash_f32_value(state, self.color.3);
426 }
427}
428
429impl ModifierNodeElement for BackgroundElement {
430 type Node = BackgroundNode;
431
432 fn create(&self) -> Self::Node {
433 BackgroundNode::new(self.color)
434 }
435
436 fn update(&self, node: &mut Self::Node) {
437 if node.color != self.color {
438 node.color = self.color;
439 }
441 }
442
443 fn capabilities(&self) -> NodeCapabilities {
444 NodeCapabilities::DRAW
445 }
446}
447
448#[derive(Debug)]
454pub struct CornerShapeNode {
455 shape: RoundedCornerShape,
456 state: NodeState,
457}
458
459impl CornerShapeNode {
460 pub fn new(shape: RoundedCornerShape) -> Self {
461 Self {
462 shape,
463 state: NodeState::new(),
464 }
465 }
466
467 pub fn shape(&self) -> RoundedCornerShape {
468 self.shape
469 }
470}
471
472impl DelegatableNode for CornerShapeNode {
473 fn node_state(&self) -> &NodeState {
474 &self.state
475 }
476}
477
478impl ModifierNode for CornerShapeNode {
479 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
480 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
481 }
482
483 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
484 Some(self)
485 }
486
487 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
488 Some(self)
489 }
490}
491
492impl DrawModifierNode for CornerShapeNode {
493 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
494}
495
496#[derive(Debug, Clone, PartialEq)]
498pub struct CornerShapeElement {
499 shape: RoundedCornerShape,
500}
501
502impl CornerShapeElement {
503 pub fn new(shape: RoundedCornerShape) -> Self {
504 Self { shape }
505 }
506}
507
508impl Hash for CornerShapeElement {
509 fn hash<H: Hasher>(&self, state: &mut H) {
510 let radii = self.shape.radii();
511 hash_f32_value(state, radii.top_left);
512 hash_f32_value(state, radii.top_right);
513 hash_f32_value(state, radii.bottom_right);
514 hash_f32_value(state, radii.bottom_left);
515 }
516}
517
518impl ModifierNodeElement for CornerShapeElement {
519 type Node = CornerShapeNode;
520
521 fn create(&self) -> Self::Node {
522 CornerShapeNode::new(self.shape)
523 }
524
525 fn update(&self, node: &mut Self::Node) {
526 if node.shape != self.shape {
527 node.shape = self.shape;
528 }
530 }
531
532 fn capabilities(&self) -> NodeCapabilities {
533 NodeCapabilities::DRAW
534 }
535}
536
537#[derive(Debug)]
543pub struct GraphicsLayerNode {
544 layer: GraphicsLayer,
545 state: NodeState,
546}
547
548impl GraphicsLayerNode {
549 pub fn new(layer: GraphicsLayer) -> Self {
550 Self {
551 layer,
552 state: NodeState::new(),
553 }
554 }
555
556 pub fn layer(&self) -> GraphicsLayer {
557 self.layer
558 }
559}
560
561impl DelegatableNode for GraphicsLayerNode {
562 fn node_state(&self) -> &NodeState {
563 &self.state
564 }
565}
566
567impl ModifierNode for GraphicsLayerNode {
568 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
569 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
570 }
571}
572
573#[derive(Debug, Clone, PartialEq)]
575pub struct GraphicsLayerElement {
576 layer: GraphicsLayer,
577}
578
579impl GraphicsLayerElement {
580 pub fn new(layer: GraphicsLayer) -> Self {
581 Self { layer }
582 }
583}
584
585impl Hash for GraphicsLayerElement {
586 fn hash<H: Hasher>(&self, state: &mut H) {
587 hash_graphics_layer(state, self.layer);
588 }
589}
590
591impl ModifierNodeElement for GraphicsLayerElement {
592 type Node = GraphicsLayerNode;
593
594 fn create(&self) -> Self::Node {
595 GraphicsLayerNode::new(self.layer)
596 }
597
598 fn update(&self, node: &mut Self::Node) {
599 if node.layer != self.layer {
600 node.layer = self.layer;
601 }
602 }
603
604 fn capabilities(&self) -> NodeCapabilities {
605 NodeCapabilities::DRAW
606 }
607}
608
609#[derive(Debug)]
617pub struct SizeNode {
618 min_width: Option<f32>,
619 max_width: Option<f32>,
620 min_height: Option<f32>,
621 max_height: Option<f32>,
622 enforce_incoming: bool,
623 state: NodeState,
624}
625
626impl SizeNode {
627 pub fn new(
628 min_width: Option<f32>,
629 max_width: Option<f32>,
630 min_height: Option<f32>,
631 max_height: Option<f32>,
632 enforce_incoming: bool,
633 ) -> Self {
634 Self {
635 min_width,
636 max_width,
637 min_height,
638 max_height,
639 enforce_incoming,
640 state: NodeState::new(),
641 }
642 }
643
644 fn target_constraints(&self) -> Constraints {
646 let max_width = self.max_width.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
647 let max_height = self.max_height.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
648
649 let min_width = self
650 .min_width
651 .map(|v| {
652 let clamped = v.clamp(0.0, max_width);
653 if clamped == f32::INFINITY {
654 0.0
655 } else {
656 clamped
657 }
658 })
659 .unwrap_or(0.0);
660
661 let min_height = self
662 .min_height
663 .map(|v| {
664 let clamped = v.clamp(0.0, max_height);
665 if clamped == f32::INFINITY {
666 0.0
667 } else {
668 clamped
669 }
670 })
671 .unwrap_or(0.0);
672
673 Constraints {
674 min_width,
675 max_width,
676 min_height,
677 max_height,
678 }
679 }
680
681 pub fn min_width(&self) -> Option<f32> {
682 self.min_width
683 }
684
685 pub fn max_width(&self) -> Option<f32> {
686 self.max_width
687 }
688
689 pub fn min_height(&self) -> Option<f32> {
690 self.min_height
691 }
692
693 pub fn max_height(&self) -> Option<f32> {
694 self.max_height
695 }
696
697 pub fn enforce_incoming(&self) -> bool {
698 self.enforce_incoming
699 }
700}
701
702impl DelegatableNode for SizeNode {
703 fn node_state(&self) -> &NodeState {
704 &self.state
705 }
706}
707
708impl ModifierNode for SizeNode {
709 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
710 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
711 }
712
713 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
714 Some(self)
715 }
716
717 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
718 Some(self)
719 }
720}
721
722impl LayoutModifierNode for SizeNode {
723 fn measure(
724 &self,
725 _context: &mut dyn ModifierNodeContext,
726 measurable: &dyn Measurable,
727 constraints: Constraints,
728 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
729 let target = self.target_constraints();
730
731 let wrapped_constraints = if self.enforce_incoming {
732 Constraints {
734 min_width: target
735 .min_width
736 .max(constraints.min_width)
737 .min(constraints.max_width),
738 max_width: target
739 .max_width
740 .min(constraints.max_width)
741 .max(constraints.min_width),
742 min_height: target
743 .min_height
744 .max(constraints.min_height)
745 .min(constraints.max_height),
746 max_height: target
747 .max_height
748 .min(constraints.max_height)
749 .max(constraints.min_height),
750 }
751 } else {
752 let resolved_min_width = if self.min_width.is_some() {
754 target.min_width
755 } else {
756 constraints.min_width.min(target.max_width)
757 };
758 let resolved_max_width = if self.max_width.is_some() {
759 target.max_width
760 } else {
761 constraints.max_width.max(target.min_width)
762 };
763 let resolved_min_height = if self.min_height.is_some() {
764 target.min_height
765 } else {
766 constraints.min_height.min(target.max_height)
767 };
768 let resolved_max_height = if self.max_height.is_some() {
769 target.max_height
770 } else {
771 constraints.max_height.max(target.min_height)
772 };
773
774 Constraints {
775 min_width: resolved_min_width,
776 max_width: resolved_max_width,
777 min_height: resolved_min_height,
778 max_height: resolved_max_height,
779 }
780 };
781
782 let placeable = measurable.measure(wrapped_constraints);
783 let measured_width = placeable.width();
784 let measured_height = placeable.height();
785
786 let result_width = if self.min_width.is_some()
790 && self.max_width.is_some()
791 && self.min_width == self.max_width
792 && target.min_width >= wrapped_constraints.min_width
793 && target.min_width <= wrapped_constraints.max_width
794 {
795 target.min_width
796 } else {
797 measured_width
798 };
799
800 let result_height = if self.min_height.is_some()
801 && self.max_height.is_some()
802 && self.min_height == self.max_height
803 && target.min_height >= wrapped_constraints.min_height
804 && target.min_height <= wrapped_constraints.max_height
805 {
806 target.min_height
807 } else {
808 measured_height
809 };
810
811 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
813 width: result_width,
814 height: result_height,
815 })
816 }
817
818 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
819 let target = self.target_constraints();
820 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
821 target.max_width
822 } else {
823 let child_height = if self.enforce_incoming {
824 height
825 } else {
826 height.clamp(target.min_height, target.max_height)
827 };
828 measurable
829 .min_intrinsic_width(child_height)
830 .clamp(target.min_width, target.max_width)
831 }
832 }
833
834 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
835 let target = self.target_constraints();
836 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
837 target.max_width
838 } else {
839 let child_height = if self.enforce_incoming {
840 height
841 } else {
842 height.clamp(target.min_height, target.max_height)
843 };
844 measurable
845 .max_intrinsic_width(child_height)
846 .clamp(target.min_width, target.max_width)
847 }
848 }
849
850 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
851 let target = self.target_constraints();
852 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
853 target.max_height
854 } else {
855 let child_width = if self.enforce_incoming {
856 width
857 } else {
858 width.clamp(target.min_width, target.max_width)
859 };
860 measurable
861 .min_intrinsic_height(child_width)
862 .clamp(target.min_height, target.max_height)
863 }
864 }
865
866 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
867 let target = self.target_constraints();
868 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
869 target.max_height
870 } else {
871 let child_width = if self.enforce_incoming {
872 width
873 } else {
874 width.clamp(target.min_width, target.max_width)
875 };
876 measurable
877 .max_intrinsic_height(child_width)
878 .clamp(target.min_height, target.max_height)
879 }
880 }
881
882 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
883 Some(Box::new(SizeMeasurementProxy {
884 min_width: self.min_width,
885 max_width: self.max_width,
886 min_height: self.min_height,
887 max_height: self.max_height,
888 enforce_incoming: self.enforce_incoming,
889 }))
890 }
891}
892
893struct SizeMeasurementProxy {
898 min_width: Option<f32>,
899 max_width: Option<f32>,
900 min_height: Option<f32>,
901 max_height: Option<f32>,
902 enforce_incoming: bool,
903}
904
905impl SizeMeasurementProxy {
906 fn target_constraints(&self) -> Constraints {
909 let max_width = self.max_width.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
910 let max_height = self.max_height.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
911
912 let min_width = self
913 .min_width
914 .map(|v| {
915 let clamped = v.clamp(0.0, max_width);
916 if clamped == f32::INFINITY {
917 0.0
918 } else {
919 clamped
920 }
921 })
922 .unwrap_or(0.0);
923
924 let min_height = self
925 .min_height
926 .map(|v| {
927 let clamped = v.clamp(0.0, max_height);
928 if clamped == f32::INFINITY {
929 0.0
930 } else {
931 clamped
932 }
933 })
934 .unwrap_or(0.0);
935
936 Constraints {
937 min_width,
938 max_width,
939 min_height,
940 max_height,
941 }
942 }
943}
944
945impl MeasurementProxy for SizeMeasurementProxy {
946 fn measure_proxy(
947 &self,
948 _context: &mut dyn ModifierNodeContext,
949 wrapped: &dyn Measurable,
950 constraints: Constraints,
951 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
952 let target = self.target_constraints();
954
955 let wrapped_constraints = if self.enforce_incoming {
956 Constraints {
958 min_width: target
959 .min_width
960 .max(constraints.min_width)
961 .min(constraints.max_width),
962 max_width: target
963 .max_width
964 .min(constraints.max_width)
965 .max(constraints.min_width),
966 min_height: target
967 .min_height
968 .max(constraints.min_height)
969 .min(constraints.max_height),
970 max_height: target
971 .max_height
972 .min(constraints.max_height)
973 .max(constraints.min_height),
974 }
975 } else {
976 let resolved_min_width = if self.min_width.is_some() {
978 target.min_width
979 } else {
980 constraints.min_width.min(target.max_width)
981 };
982 let resolved_max_width = if self.max_width.is_some() {
983 target.max_width
984 } else {
985 constraints.max_width.max(target.min_width)
986 };
987 let resolved_min_height = if self.min_height.is_some() {
988 target.min_height
989 } else {
990 constraints.min_height.min(target.max_height)
991 };
992 let resolved_max_height = if self.max_height.is_some() {
993 target.max_height
994 } else {
995 constraints.max_height.max(target.min_height)
996 };
997
998 Constraints {
999 min_width: resolved_min_width,
1000 max_width: resolved_max_width,
1001 min_height: resolved_min_height,
1002 max_height: resolved_max_height,
1003 }
1004 };
1005
1006 let placeable = wrapped.measure(wrapped_constraints);
1007 let measured_width = placeable.width();
1008 let measured_height = placeable.height();
1009
1010 let result_width = if self.min_width.is_some()
1013 && self.max_width.is_some()
1014 && self.min_width == self.max_width
1015 && target.min_width >= wrapped_constraints.min_width
1016 && target.min_width <= wrapped_constraints.max_width
1017 {
1018 target.min_width
1019 } else {
1020 measured_width
1021 };
1022
1023 let result_height = if self.min_height.is_some()
1024 && self.max_height.is_some()
1025 && self.min_height == self.max_height
1026 && target.min_height >= wrapped_constraints.min_height
1027 && target.min_height <= wrapped_constraints.max_height
1028 {
1029 target.min_height
1030 } else {
1031 measured_height
1032 };
1033
1034 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
1036 width: result_width,
1037 height: result_height,
1038 })
1039 }
1040
1041 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1042 let target = self.target_constraints();
1043 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1044 target.max_width
1045 } else {
1046 let child_height = if self.enforce_incoming {
1047 height
1048 } else {
1049 height.clamp(target.min_height, target.max_height)
1050 };
1051 wrapped
1052 .min_intrinsic_width(child_height)
1053 .clamp(target.min_width, target.max_width)
1054 }
1055 }
1056
1057 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1058 let target = self.target_constraints();
1059 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1060 target.max_width
1061 } else {
1062 let child_height = if self.enforce_incoming {
1063 height
1064 } else {
1065 height.clamp(target.min_height, target.max_height)
1066 };
1067 wrapped
1068 .max_intrinsic_width(child_height)
1069 .clamp(target.min_width, target.max_width)
1070 }
1071 }
1072
1073 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1074 let target = self.target_constraints();
1075 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1076 target.max_height
1077 } else {
1078 let child_width = if self.enforce_incoming {
1079 width
1080 } else {
1081 width.clamp(target.min_width, target.max_width)
1082 };
1083 wrapped
1084 .min_intrinsic_height(child_width)
1085 .clamp(target.min_height, target.max_height)
1086 }
1087 }
1088
1089 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1090 let target = self.target_constraints();
1091 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1092 target.max_height
1093 } else {
1094 let child_width = if self.enforce_incoming {
1095 width
1096 } else {
1097 width.clamp(target.min_width, target.max_width)
1098 };
1099 wrapped
1100 .max_intrinsic_height(child_width)
1101 .clamp(target.min_height, target.max_height)
1102 }
1103 }
1104}
1105
1106#[derive(Debug, Clone, PartialEq)]
1110pub struct SizeElement {
1111 min_width: Option<f32>,
1112 max_width: Option<f32>,
1113 min_height: Option<f32>,
1114 max_height: Option<f32>,
1115 enforce_incoming: bool,
1116}
1117
1118impl SizeElement {
1119 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
1120 Self {
1121 min_width: width,
1122 max_width: width,
1123 min_height: height,
1124 max_height: height,
1125 enforce_incoming: true,
1126 }
1127 }
1128
1129 pub fn with_constraints(
1130 min_width: Option<f32>,
1131 max_width: Option<f32>,
1132 min_height: Option<f32>,
1133 max_height: Option<f32>,
1134 enforce_incoming: bool,
1135 ) -> Self {
1136 Self {
1137 min_width,
1138 max_width,
1139 min_height,
1140 max_height,
1141 enforce_incoming,
1142 }
1143 }
1144}
1145
1146impl Hash for SizeElement {
1147 fn hash<H: Hasher>(&self, state: &mut H) {
1148 hash_option_f32(state, self.min_width);
1149 hash_option_f32(state, self.max_width);
1150 hash_option_f32(state, self.min_height);
1151 hash_option_f32(state, self.max_height);
1152 self.enforce_incoming.hash(state);
1153 }
1154}
1155
1156impl ModifierNodeElement for SizeElement {
1157 type Node = SizeNode;
1158
1159 fn create(&self) -> Self::Node {
1160 SizeNode::new(
1161 self.min_width,
1162 self.max_width,
1163 self.min_height,
1164 self.max_height,
1165 self.enforce_incoming,
1166 )
1167 }
1168
1169 fn update(&self, node: &mut Self::Node) {
1170 if node.min_width != self.min_width
1171 || node.max_width != self.max_width
1172 || node.min_height != self.min_height
1173 || node.max_height != self.max_height
1174 || node.enforce_incoming != self.enforce_incoming
1175 {
1176 node.min_width = self.min_width;
1177 node.max_width = self.max_width;
1178 node.min_height = self.min_height;
1179 node.max_height = self.max_height;
1180 node.enforce_incoming = self.enforce_incoming;
1181 }
1182 }
1183
1184 fn capabilities(&self) -> NodeCapabilities {
1185 NodeCapabilities::LAYOUT
1186 }
1187}
1188
1189use cranpose_foundation::DRAG_THRESHOLD;
1196
1197use std::cell::RefCell;
1198
1199pub struct ClickableNode {
1204 on_click: Rc<dyn Fn(Point)>,
1205 state: NodeState,
1206 press_position: Rc<RefCell<Option<Point>>>,
1208 cached_handler: Rc<dyn Fn(PointerEvent)>,
1210}
1211
1212impl std::fmt::Debug for ClickableNode {
1213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1214 f.debug_struct("ClickableNode").finish()
1215 }
1216}
1217
1218impl ClickableNode {
1219 pub fn new(on_click: impl Fn(Point) + 'static) -> Self {
1220 Self::with_handler(Rc::new(on_click))
1221 }
1222
1223 pub fn with_handler(on_click: Rc<dyn Fn(Point)>) -> Self {
1224 let press_position = Rc::new(RefCell::new(None));
1225 let cached_handler = Self::create_handler(on_click.clone(), press_position.clone());
1226 Self {
1227 on_click,
1228 state: NodeState::new(),
1229 press_position,
1230 cached_handler,
1231 }
1232 }
1233
1234 fn create_handler(
1235 handler: Rc<dyn Fn(Point)>,
1236 press_position: Rc<RefCell<Option<Point>>>,
1237 ) -> Rc<dyn Fn(PointerEvent)> {
1238 Rc::new(move |event: PointerEvent| {
1239 if event.is_consumed() {
1241 *press_position.borrow_mut() = None;
1243 return;
1244 }
1245
1246 match event.kind {
1247 PointerEventKind::Down => {
1248 *press_position.borrow_mut() = Some(Point {
1250 x: event.global_position.x,
1251 y: event.global_position.y,
1252 });
1253 }
1254 PointerEventKind::Move => {
1255 }
1257 PointerEventKind::Up => {
1258 let press_pos_value = *press_position.borrow();
1260
1261 let should_click = if let Some(press_pos) = press_pos_value {
1262 let dx = event.global_position.x - press_pos.x;
1263 let dy = event.global_position.y - press_pos.y;
1264 let distance = (dx * dx + dy * dy).sqrt();
1265 distance <= DRAG_THRESHOLD
1266 } else {
1267 true
1271 };
1272
1273 *press_position.borrow_mut() = None;
1275
1276 if should_click {
1277 handler(Point {
1278 x: event.position.x,
1279 y: event.position.y,
1280 });
1281 event.consume();
1282 }
1283 }
1284 PointerEventKind::Cancel => {
1285 *press_position.borrow_mut() = None;
1287 }
1288 }
1289 })
1290 }
1291
1292 pub fn handler(&self) -> Rc<dyn Fn(Point)> {
1293 self.on_click.clone()
1294 }
1295}
1296
1297impl DelegatableNode for ClickableNode {
1298 fn node_state(&self) -> &NodeState {
1299 &self.state
1300 }
1301}
1302
1303impl ModifierNode for ClickableNode {
1304 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1305 context.invalidate(cranpose_foundation::InvalidationKind::PointerInput);
1306 }
1307
1308 fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
1309 Some(self)
1310 }
1311
1312 fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
1313 Some(self)
1314 }
1315}
1316
1317impl PointerInputNode for ClickableNode {
1318 fn on_pointer_event(
1319 &mut self,
1320 _context: &mut dyn ModifierNodeContext,
1321 event: &PointerEvent,
1322 ) -> bool {
1323 (self.cached_handler)(event.clone());
1326 event.is_consumed()
1327 }
1328
1329 fn hit_test(&self, _x: f32, _y: f32) -> bool {
1330 true
1332 }
1333
1334 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
1335 Some(self.cached_handler.clone())
1338 }
1339}
1340
1341#[derive(Clone)]
1343pub struct ClickableElement {
1344 on_click: Rc<dyn Fn(Point)>,
1345}
1346
1347impl ClickableElement {
1348 pub fn new(on_click: impl Fn(Point) + 'static) -> Self {
1349 Self {
1350 on_click: Rc::new(on_click),
1351 }
1352 }
1353
1354 pub fn with_handler(on_click: Rc<dyn Fn(Point)>) -> Self {
1355 Self { on_click }
1356 }
1357}
1358
1359impl std::fmt::Debug for ClickableElement {
1360 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1361 f.debug_struct("ClickableElement").finish()
1362 }
1363}
1364
1365impl PartialEq for ClickableElement {
1366 fn eq(&self, _other: &Self) -> bool {
1367 true
1371 }
1372}
1373
1374impl Eq for ClickableElement {}
1375
1376impl Hash for ClickableElement {
1377 fn hash<H: Hasher>(&self, state: &mut H) {
1378 "clickable".hash(state);
1380 }
1381}
1382
1383impl ModifierNodeElement for ClickableElement {
1384 type Node = ClickableNode;
1385
1386 fn create(&self) -> Self::Node {
1387 ClickableNode::with_handler(self.on_click.clone())
1388 }
1389
1390 fn update(&self, node: &mut Self::Node) {
1396 node.on_click = self.on_click.clone();
1399 node.cached_handler =
1401 ClickableNode::create_handler(node.on_click.clone(), node.press_position.clone());
1402 }
1403
1404 fn capabilities(&self) -> NodeCapabilities {
1405 NodeCapabilities::POINTER_INPUT
1406 }
1407
1408 fn always_update(&self) -> bool {
1409 true
1411 }
1412}
1413
1414pub struct PointerEventHandlerNode {
1420 handler: Rc<dyn Fn(PointerEvent)>,
1421 state: NodeState,
1422}
1423
1424impl std::fmt::Debug for PointerEventHandlerNode {
1425 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1426 f.debug_struct("PointerEventHandlerNode").finish()
1427 }
1428}
1429
1430impl PointerEventHandlerNode {
1431 pub fn new(handler: Rc<dyn Fn(PointerEvent)>) -> Self {
1432 Self {
1433 handler,
1434 state: NodeState::new(),
1435 }
1436 }
1437
1438 #[allow(dead_code)] pub fn handler(&self) -> Rc<dyn Fn(PointerEvent)> {
1440 self.handler.clone()
1441 }
1442}
1443
1444impl DelegatableNode for PointerEventHandlerNode {
1445 fn node_state(&self) -> &NodeState {
1446 &self.state
1447 }
1448}
1449
1450impl ModifierNode for PointerEventHandlerNode {
1451 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1452 context.invalidate(cranpose_foundation::InvalidationKind::PointerInput);
1453 }
1454
1455 fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
1456 Some(self)
1457 }
1458
1459 fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
1460 Some(self)
1461 }
1462}
1463
1464impl PointerInputNode for PointerEventHandlerNode {
1465 fn on_pointer_event(
1466 &mut self,
1467 _context: &mut dyn ModifierNodeContext,
1468 event: &PointerEvent,
1469 ) -> bool {
1470 (self.handler)(event.clone());
1471 false
1472 }
1473
1474 fn hit_test(&self, _x: f32, _y: f32) -> bool {
1475 true
1476 }
1477
1478 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
1479 Some(self.handler.clone())
1480 }
1481}
1482
1483#[derive(Clone)]
1485pub struct PointerEventHandlerElement {
1486 handler: Rc<dyn Fn(PointerEvent)>,
1487}
1488
1489impl PointerEventHandlerElement {
1490 #[allow(dead_code)] pub fn new(handler: Rc<dyn Fn(PointerEvent)>) -> Self {
1492 Self { handler }
1493 }
1494}
1495
1496impl std::fmt::Debug for PointerEventHandlerElement {
1497 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1498 f.debug_struct("PointerEventHandlerElement").finish()
1499 }
1500}
1501
1502impl PartialEq for PointerEventHandlerElement {
1503 fn eq(&self, other: &Self) -> bool {
1504 Rc::ptr_eq(&self.handler, &other.handler)
1505 }
1506}
1507
1508impl Eq for PointerEventHandlerElement {}
1509
1510impl Hash for PointerEventHandlerElement {
1511 fn hash<H: Hasher>(&self, state: &mut H) {
1512 let ptr = Rc::as_ptr(&self.handler) as *const ();
1513 (ptr as usize).hash(state);
1514 }
1515}
1516
1517impl ModifierNodeElement for PointerEventHandlerElement {
1518 type Node = PointerEventHandlerNode;
1519
1520 fn create(&self) -> Self::Node {
1521 PointerEventHandlerNode::new(self.handler.clone())
1522 }
1523
1524 fn update(&self, node: &mut Self::Node) {
1525 node.handler = self.handler.clone();
1526 }
1527
1528 fn capabilities(&self) -> NodeCapabilities {
1529 NodeCapabilities::POINTER_INPUT
1530 }
1531}
1532
1533#[derive(Debug)]
1539pub struct AlphaNode {
1540 alpha: f32,
1541 state: NodeState,
1542}
1543
1544impl AlphaNode {
1545 pub fn new(alpha: f32) -> Self {
1546 Self {
1547 alpha: alpha.clamp(0.0, 1.0),
1548 state: NodeState::new(),
1549 }
1550 }
1551}
1552
1553impl DelegatableNode for AlphaNode {
1554 fn node_state(&self) -> &NodeState {
1555 &self.state
1556 }
1557}
1558
1559impl ModifierNode for AlphaNode {
1560 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1561 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1562 }
1563
1564 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1565 Some(self)
1566 }
1567
1568 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1569 Some(self)
1570 }
1571}
1572
1573impl DrawModifierNode for AlphaNode {
1574 fn draw(&self, _draw_scope: &mut dyn DrawScope) {
1575 }
1583}
1584
1585#[derive(Debug, Clone, PartialEq)]
1587pub struct AlphaElement {
1588 alpha: f32,
1589}
1590
1591impl AlphaElement {
1592 pub fn new(alpha: f32) -> Self {
1593 Self {
1594 alpha: alpha.clamp(0.0, 1.0),
1595 }
1596 }
1597}
1598
1599impl Hash for AlphaElement {
1600 fn hash<H: Hasher>(&self, state: &mut H) {
1601 hash_f32_value(state, self.alpha);
1602 }
1603}
1604
1605impl ModifierNodeElement for AlphaElement {
1606 type Node = AlphaNode;
1607
1608 fn create(&self) -> Self::Node {
1609 AlphaNode::new(self.alpha)
1610 }
1611
1612 fn update(&self, node: &mut Self::Node) {
1613 let new_alpha = self.alpha.clamp(0.0, 1.0);
1614 if (node.alpha - new_alpha).abs() > f32::EPSILON {
1615 node.alpha = new_alpha;
1616 }
1618 }
1619
1620 fn capabilities(&self) -> NodeCapabilities {
1621 NodeCapabilities::DRAW
1622 }
1623}
1624
1625#[derive(Debug)]
1631pub struct ClipToBoundsNode {
1632 state: NodeState,
1633}
1634
1635impl ClipToBoundsNode {
1636 pub fn new() -> Self {
1637 Self {
1638 state: NodeState::new(),
1639 }
1640 }
1641}
1642
1643impl DelegatableNode for ClipToBoundsNode {
1644 fn node_state(&self) -> &NodeState {
1645 &self.state
1646 }
1647}
1648
1649impl ModifierNode for ClipToBoundsNode {
1650 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1651 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1652 }
1653
1654 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1655 Some(self)
1656 }
1657
1658 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1659 Some(self)
1660 }
1661}
1662
1663impl DrawModifierNode for ClipToBoundsNode {
1664 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1665}
1666
1667#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1669pub struct ClipToBoundsElement;
1670
1671impl ClipToBoundsElement {
1672 pub fn new() -> Self {
1673 Self
1674 }
1675}
1676
1677impl ModifierNodeElement for ClipToBoundsElement {
1678 type Node = ClipToBoundsNode;
1679
1680 fn create(&self) -> Self::Node {
1681 ClipToBoundsNode::new()
1682 }
1683
1684 fn update(&self, _node: &mut Self::Node) {}
1685
1686 fn capabilities(&self) -> NodeCapabilities {
1687 NodeCapabilities::DRAW
1688 }
1689}
1690
1691pub struct DrawCommandNode {
1697 commands: Vec<DrawCommand>,
1698 state: NodeState,
1699}
1700
1701impl DrawCommandNode {
1702 pub fn new(commands: Vec<DrawCommand>) -> Self {
1703 Self {
1704 commands,
1705 state: NodeState::new(),
1706 }
1707 }
1708
1709 pub fn commands(&self) -> &[DrawCommand] {
1710 &self.commands
1711 }
1712}
1713
1714impl DelegatableNode for DrawCommandNode {
1715 fn node_state(&self) -> &NodeState {
1716 &self.state
1717 }
1718}
1719
1720impl ModifierNode for DrawCommandNode {
1721 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1722 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1723 }
1724
1725 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1726 Some(self)
1727 }
1728
1729 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1730 Some(self)
1731 }
1732}
1733
1734impl DrawModifierNode for DrawCommandNode {
1735 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1736}
1737
1738fn draw_command_tag(cmd: &DrawCommand) -> u8 {
1739 match cmd {
1740 DrawCommand::Behind(_) => 0,
1741 DrawCommand::Overlay(_) => 1,
1742 }
1743}
1744
1745#[derive(Clone)]
1747pub struct DrawCommandElement {
1748 commands: Vec<DrawCommand>,
1749}
1750
1751impl DrawCommandElement {
1752 pub fn new(command: DrawCommand) -> Self {
1753 Self {
1754 commands: vec![command],
1755 }
1756 }
1757
1758 pub fn from_commands(commands: Vec<DrawCommand>) -> Self {
1759 Self { commands }
1760 }
1761}
1762
1763impl std::fmt::Debug for DrawCommandElement {
1764 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1765 f.debug_struct("DrawCommandElement")
1766 .field("commands", &self.commands.len())
1767 .finish()
1768 }
1769}
1770
1771impl PartialEq for DrawCommandElement {
1772 fn eq(&self, other: &Self) -> bool {
1773 if self.commands.len() != other.commands.len() {
1777 return false;
1778 }
1779 self.commands
1780 .iter()
1781 .zip(other.commands.iter())
1782 .all(|(a, b)| draw_command_tag(a) == draw_command_tag(b))
1783 }
1784}
1785
1786impl Eq for DrawCommandElement {}
1787
1788impl std::hash::Hash for DrawCommandElement {
1789 fn hash<H: Hasher>(&self, state: &mut H) {
1790 "draw_commands".hash(state);
1792 self.commands.len().hash(state);
1793 for command in &self.commands {
1794 draw_command_tag(command).hash(state);
1795 }
1796 }
1797}
1798
1799impl ModifierNodeElement for DrawCommandElement {
1800 type Node = DrawCommandNode;
1801
1802 fn create(&self) -> Self::Node {
1803 DrawCommandNode::new(self.commands.clone())
1804 }
1805
1806 fn update(&self, node: &mut Self::Node) {
1807 node.commands = self.commands.clone();
1808 }
1809
1810 fn capabilities(&self) -> NodeCapabilities {
1811 NodeCapabilities::DRAW
1812 }
1813
1814 fn always_update(&self) -> bool {
1815 true
1817 }
1818}
1819
1820#[derive(Debug)]
1828pub struct OffsetNode {
1829 x: f32,
1830 y: f32,
1831 rtl_aware: bool,
1832 state: NodeState,
1833}
1834
1835impl OffsetNode {
1836 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
1837 Self {
1838 x,
1839 y,
1840 rtl_aware,
1841 state: NodeState::new(),
1842 }
1843 }
1844
1845 pub fn offset(&self) -> Point {
1846 Point {
1847 x: self.x,
1848 y: self.y,
1849 }
1850 }
1851
1852 pub fn rtl_aware(&self) -> bool {
1853 self.rtl_aware
1854 }
1855}
1856
1857impl DelegatableNode for OffsetNode {
1858 fn node_state(&self) -> &NodeState {
1859 &self.state
1860 }
1861}
1862
1863impl ModifierNode for OffsetNode {
1864 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1865 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
1866 }
1867
1868 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
1869 Some(self)
1870 }
1871
1872 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
1873 Some(self)
1874 }
1875}
1876
1877impl LayoutModifierNode for OffsetNode {
1878 fn measure(
1879 &self,
1880 _context: &mut dyn ModifierNodeContext,
1881 measurable: &dyn Measurable,
1882 constraints: Constraints,
1883 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
1884 let placeable = measurable.measure(constraints);
1886
1887 cranpose_ui_layout::LayoutModifierMeasureResult::new(
1889 Size {
1890 width: placeable.width(),
1891 height: placeable.height(),
1892 },
1893 self.x, self.y, )
1896 }
1897
1898 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
1899 measurable.min_intrinsic_width(height)
1900 }
1901
1902 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
1903 measurable.max_intrinsic_width(height)
1904 }
1905
1906 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
1907 measurable.min_intrinsic_height(width)
1908 }
1909
1910 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
1911 measurable.max_intrinsic_height(width)
1912 }
1913
1914 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
1915 Some(Box::new(OffsetMeasurementProxy {
1916 x: self.x,
1917 y: self.y,
1918 rtl_aware: self.rtl_aware,
1919 }))
1920 }
1921}
1922
1923struct OffsetMeasurementProxy {
1929 x: f32,
1930 y: f32,
1931 #[allow(dead_code)]
1932 rtl_aware: bool,
1933}
1934
1935impl MeasurementProxy for OffsetMeasurementProxy {
1936 fn measure_proxy(
1937 &self,
1938 _context: &mut dyn ModifierNodeContext,
1939 wrapped: &dyn Measurable,
1940 constraints: Constraints,
1941 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
1942 let placeable = wrapped.measure(constraints);
1944
1945 cranpose_ui_layout::LayoutModifierMeasureResult::new(
1947 Size {
1948 width: placeable.width(),
1949 height: placeable.height(),
1950 },
1951 self.x, self.y, )
1954 }
1955
1956 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1957 wrapped.min_intrinsic_width(height)
1958 }
1959
1960 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1961 wrapped.max_intrinsic_width(height)
1962 }
1963
1964 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1965 wrapped.min_intrinsic_height(width)
1966 }
1967
1968 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1969 wrapped.max_intrinsic_height(width)
1970 }
1971}
1972
1973#[derive(Debug, Clone, PartialEq)]
1977pub struct OffsetElement {
1978 x: f32,
1979 y: f32,
1980 rtl_aware: bool,
1981}
1982
1983impl OffsetElement {
1984 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
1985 Self { x, y, rtl_aware }
1986 }
1987}
1988
1989impl Hash for OffsetElement {
1990 fn hash<H: Hasher>(&self, state: &mut H) {
1991 hash_f32_value(state, self.x);
1992 hash_f32_value(state, self.y);
1993 self.rtl_aware.hash(state);
1994 }
1995}
1996
1997impl ModifierNodeElement for OffsetElement {
1998 type Node = OffsetNode;
1999
2000 fn create(&self) -> Self::Node {
2001 OffsetNode::new(self.x, self.y, self.rtl_aware)
2002 }
2003
2004 fn update(&self, node: &mut Self::Node) {
2005 if node.x != self.x || node.y != self.y || node.rtl_aware != self.rtl_aware {
2006 node.x = self.x;
2007 node.y = self.y;
2008 node.rtl_aware = self.rtl_aware;
2009 }
2010 }
2011
2012 fn capabilities(&self) -> NodeCapabilities {
2013 NodeCapabilities::LAYOUT
2014 }
2015}
2016
2017#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2023pub enum FillDirection {
2024 Horizontal,
2025 Vertical,
2026 Both,
2027}
2028
2029#[derive(Debug)]
2033pub struct FillNode {
2034 direction: FillDirection,
2035 fraction: f32,
2036 state: NodeState,
2037}
2038
2039impl FillNode {
2040 pub fn new(direction: FillDirection, fraction: f32) -> Self {
2041 Self {
2042 direction,
2043 fraction,
2044 state: NodeState::new(),
2045 }
2046 }
2047
2048 pub fn direction(&self) -> FillDirection {
2049 self.direction
2050 }
2051
2052 pub fn fraction(&self) -> f32 {
2053 self.fraction
2054 }
2055}
2056
2057impl DelegatableNode for FillNode {
2058 fn node_state(&self) -> &NodeState {
2059 &self.state
2060 }
2061}
2062
2063impl ModifierNode for FillNode {
2064 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2065 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2066 }
2067
2068 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
2069 Some(self)
2070 }
2071
2072 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
2073 Some(self)
2074 }
2075}
2076
2077impl LayoutModifierNode for FillNode {
2078 fn measure(
2079 &self,
2080 _context: &mut dyn ModifierNodeContext,
2081 measurable: &dyn Measurable,
2082 constraints: Constraints,
2083 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2084 let (fill_width, child_min_width, child_max_width) = if self.direction
2086 != FillDirection::Vertical
2087 && constraints.max_width != f32::INFINITY
2088 {
2089 let width = (constraints.max_width * self.fraction)
2090 .round()
2091 .clamp(constraints.min_width, constraints.max_width);
2092 (width, width, width)
2094 } else {
2095 (
2096 constraints.max_width,
2097 constraints.min_width,
2098 constraints.max_width,
2099 )
2100 };
2101
2102 let (fill_height, child_min_height, child_max_height) = if self.direction
2103 != FillDirection::Horizontal
2104 && constraints.max_height != f32::INFINITY
2105 {
2106 let height = (constraints.max_height * self.fraction)
2107 .round()
2108 .clamp(constraints.min_height, constraints.max_height);
2109 (height, height, height)
2111 } else {
2112 (
2113 constraints.max_height,
2114 constraints.min_height,
2115 constraints.max_height,
2116 )
2117 };
2118
2119 let fill_constraints = Constraints {
2120 min_width: child_min_width,
2121 max_width: child_max_width,
2122 min_height: child_min_height,
2123 max_height: child_max_height,
2124 };
2125
2126 let placeable = measurable.measure(fill_constraints);
2127
2128 let result_width = if self.direction != FillDirection::Vertical
2132 && constraints.max_width != f32::INFINITY
2133 {
2134 fill_width
2135 } else {
2136 placeable.width()
2137 };
2138
2139 let result_height = if self.direction != FillDirection::Horizontal
2140 && constraints.max_height != f32::INFINITY
2141 {
2142 fill_height
2143 } else {
2144 placeable.height()
2145 };
2146
2147 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2148 width: result_width,
2149 height: result_height,
2150 })
2151 }
2152
2153 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2154 measurable.min_intrinsic_width(height)
2155 }
2156
2157 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2158 measurable.max_intrinsic_width(height)
2159 }
2160
2161 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2162 measurable.min_intrinsic_height(width)
2163 }
2164
2165 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2166 measurable.max_intrinsic_height(width)
2167 }
2168
2169 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
2170 Some(Box::new(FillMeasurementProxy {
2171 direction: self.direction,
2172 fraction: self.fraction,
2173 }))
2174 }
2175}
2176
2177struct FillMeasurementProxy {
2182 direction: FillDirection,
2183 fraction: f32,
2184}
2185
2186impl MeasurementProxy for FillMeasurementProxy {
2187 fn measure_proxy(
2188 &self,
2189 _context: &mut dyn ModifierNodeContext,
2190 wrapped: &dyn Measurable,
2191 constraints: Constraints,
2192 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2193 let (fill_width, child_min_width, child_max_width) = if self.direction
2195 != FillDirection::Vertical
2196 && constraints.max_width != f32::INFINITY
2197 {
2198 let width = (constraints.max_width * self.fraction)
2199 .round()
2200 .clamp(constraints.min_width, constraints.max_width);
2201 (width, width, width)
2202 } else {
2203 (
2204 constraints.max_width,
2205 constraints.min_width,
2206 constraints.max_width,
2207 )
2208 };
2209
2210 let (fill_height, child_min_height, child_max_height) = if self.direction
2211 != FillDirection::Horizontal
2212 && constraints.max_height != f32::INFINITY
2213 {
2214 let height = (constraints.max_height * self.fraction)
2215 .round()
2216 .clamp(constraints.min_height, constraints.max_height);
2217 (height, height, height)
2218 } else {
2219 (
2220 constraints.max_height,
2221 constraints.min_height,
2222 constraints.max_height,
2223 )
2224 };
2225
2226 let fill_constraints = Constraints {
2227 min_width: child_min_width,
2228 max_width: child_max_width,
2229 min_height: child_min_height,
2230 max_height: child_max_height,
2231 };
2232
2233 let placeable = wrapped.measure(fill_constraints);
2234
2235 let result_width = if self.direction != FillDirection::Vertical
2237 && constraints.max_width != f32::INFINITY
2238 {
2239 fill_width
2240 } else {
2241 placeable.width()
2242 };
2243
2244 let result_height = if self.direction != FillDirection::Horizontal
2245 && constraints.max_height != f32::INFINITY
2246 {
2247 fill_height
2248 } else {
2249 placeable.height()
2250 };
2251
2252 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2253 width: result_width,
2254 height: result_height,
2255 })
2256 }
2257
2258 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2259 wrapped.min_intrinsic_width(height)
2260 }
2261
2262 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2263 wrapped.max_intrinsic_width(height)
2264 }
2265
2266 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2267 wrapped.min_intrinsic_height(width)
2268 }
2269
2270 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2271 wrapped.max_intrinsic_height(width)
2272 }
2273}
2274
2275#[derive(Debug, Clone, PartialEq)]
2279pub struct FillElement {
2280 direction: FillDirection,
2281 fraction: f32,
2282}
2283
2284impl FillElement {
2285 pub fn width(fraction: f32) -> Self {
2286 Self {
2287 direction: FillDirection::Horizontal,
2288 fraction,
2289 }
2290 }
2291
2292 pub fn height(fraction: f32) -> Self {
2293 Self {
2294 direction: FillDirection::Vertical,
2295 fraction,
2296 }
2297 }
2298
2299 pub fn size(fraction: f32) -> Self {
2300 Self {
2301 direction: FillDirection::Both,
2302 fraction,
2303 }
2304 }
2305}
2306
2307impl Hash for FillElement {
2308 fn hash<H: Hasher>(&self, state: &mut H) {
2309 self.direction.hash(state);
2310 hash_f32_value(state, self.fraction);
2311 }
2312}
2313
2314impl ModifierNodeElement for FillElement {
2315 type Node = FillNode;
2316
2317 fn create(&self) -> Self::Node {
2318 FillNode::new(self.direction, self.fraction)
2319 }
2320
2321 fn update(&self, node: &mut Self::Node) {
2322 if node.direction != self.direction || node.fraction != self.fraction {
2323 node.direction = self.direction;
2324 node.fraction = self.fraction;
2325 }
2326 }
2327
2328 fn capabilities(&self) -> NodeCapabilities {
2329 NodeCapabilities::LAYOUT
2330 }
2331}
2332
2333#[derive(Debug)]
2339pub struct WeightNode {
2340 weight: f32,
2341 fill: bool,
2342 state: NodeState,
2343}
2344
2345impl WeightNode {
2346 pub fn new(weight: f32, fill: bool) -> Self {
2347 Self {
2348 weight,
2349 fill,
2350 state: NodeState::new(),
2351 }
2352 }
2353
2354 pub fn layout_weight(&self) -> LayoutWeight {
2355 LayoutWeight {
2356 weight: self.weight,
2357 fill: self.fill,
2358 }
2359 }
2360}
2361
2362impl DelegatableNode for WeightNode {
2363 fn node_state(&self) -> &NodeState {
2364 &self.state
2365 }
2366}
2367
2368impl ModifierNode for WeightNode {
2369 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2370 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2371 }
2372}
2373
2374#[derive(Debug, Clone, PartialEq)]
2376pub struct WeightElement {
2377 weight: f32,
2378 fill: bool,
2379}
2380
2381impl WeightElement {
2382 pub fn new(weight: f32, fill: bool) -> Self {
2383 Self { weight, fill }
2384 }
2385}
2386
2387impl Hash for WeightElement {
2388 fn hash<H: Hasher>(&self, state: &mut H) {
2389 hash_f32_value(state, self.weight);
2390 self.fill.hash(state);
2391 }
2392}
2393
2394impl ModifierNodeElement for WeightElement {
2395 type Node = WeightNode;
2396
2397 fn create(&self) -> Self::Node {
2398 WeightNode::new(self.weight, self.fill)
2399 }
2400
2401 fn update(&self, node: &mut Self::Node) {
2402 if node.weight != self.weight || node.fill != self.fill {
2403 node.weight = self.weight;
2404 node.fill = self.fill;
2405 }
2406 }
2407
2408 fn capabilities(&self) -> NodeCapabilities {
2409 NodeCapabilities::LAYOUT
2410 }
2411}
2412
2413#[derive(Debug)]
2419pub struct AlignmentNode {
2420 box_alignment: Option<Alignment>,
2421 column_alignment: Option<HorizontalAlignment>,
2422 row_alignment: Option<VerticalAlignment>,
2423 state: NodeState,
2424}
2425
2426impl AlignmentNode {
2427 pub fn new(
2428 box_alignment: Option<Alignment>,
2429 column_alignment: Option<HorizontalAlignment>,
2430 row_alignment: Option<VerticalAlignment>,
2431 ) -> Self {
2432 Self {
2433 box_alignment,
2434 column_alignment,
2435 row_alignment,
2436 state: NodeState::new(),
2437 }
2438 }
2439
2440 pub fn box_alignment(&self) -> Option<Alignment> {
2441 self.box_alignment
2442 }
2443
2444 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
2445 self.column_alignment
2446 }
2447
2448 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
2449 self.row_alignment
2450 }
2451}
2452
2453impl DelegatableNode for AlignmentNode {
2454 fn node_state(&self) -> &NodeState {
2455 &self.state
2456 }
2457}
2458
2459impl ModifierNode for AlignmentNode {
2460 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2461 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2462 }
2463}
2464
2465#[derive(Debug, Clone, PartialEq)]
2467pub struct AlignmentElement {
2468 box_alignment: Option<Alignment>,
2469 column_alignment: Option<HorizontalAlignment>,
2470 row_alignment: Option<VerticalAlignment>,
2471}
2472
2473impl AlignmentElement {
2474 pub fn box_alignment(alignment: Alignment) -> Self {
2475 Self {
2476 box_alignment: Some(alignment),
2477 column_alignment: None,
2478 row_alignment: None,
2479 }
2480 }
2481
2482 pub fn column_alignment(alignment: HorizontalAlignment) -> Self {
2483 Self {
2484 box_alignment: None,
2485 column_alignment: Some(alignment),
2486 row_alignment: None,
2487 }
2488 }
2489
2490 pub fn row_alignment(alignment: VerticalAlignment) -> Self {
2491 Self {
2492 box_alignment: None,
2493 column_alignment: None,
2494 row_alignment: Some(alignment),
2495 }
2496 }
2497}
2498
2499impl Hash for AlignmentElement {
2500 fn hash<H: Hasher>(&self, state: &mut H) {
2501 if let Some(alignment) = self.box_alignment {
2502 state.write_u8(1);
2503 hash_alignment(state, alignment);
2504 } else {
2505 state.write_u8(0);
2506 }
2507 if let Some(alignment) = self.column_alignment {
2508 state.write_u8(1);
2509 hash_horizontal_alignment(state, alignment);
2510 } else {
2511 state.write_u8(0);
2512 }
2513 if let Some(alignment) = self.row_alignment {
2514 state.write_u8(1);
2515 hash_vertical_alignment(state, alignment);
2516 } else {
2517 state.write_u8(0);
2518 }
2519 }
2520}
2521
2522impl ModifierNodeElement for AlignmentElement {
2523 type Node = AlignmentNode;
2524
2525 fn create(&self) -> Self::Node {
2526 AlignmentNode::new(
2527 self.box_alignment,
2528 self.column_alignment,
2529 self.row_alignment,
2530 )
2531 }
2532
2533 fn update(&self, node: &mut Self::Node) {
2534 if node.box_alignment != self.box_alignment {
2535 node.box_alignment = self.box_alignment;
2536 }
2537 if node.column_alignment != self.column_alignment {
2538 node.column_alignment = self.column_alignment;
2539 }
2540 if node.row_alignment != self.row_alignment {
2541 node.row_alignment = self.row_alignment;
2542 }
2543 }
2544
2545 fn capabilities(&self) -> NodeCapabilities {
2546 NodeCapabilities::LAYOUT
2547 }
2548}
2549
2550#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2555pub enum IntrinsicAxis {
2556 Width,
2557 Height,
2558}
2559
2560#[derive(Debug)]
2562pub struct IntrinsicSizeNode {
2563 axis: IntrinsicAxis,
2564 size: IntrinsicSize,
2565 state: NodeState,
2566}
2567
2568impl IntrinsicSizeNode {
2569 pub fn new(axis: IntrinsicAxis, size: IntrinsicSize) -> Self {
2570 Self {
2571 axis,
2572 size,
2573 state: NodeState::new(),
2574 }
2575 }
2576
2577 pub fn axis(&self) -> IntrinsicAxis {
2578 self.axis
2579 }
2580
2581 pub fn intrinsic_size(&self) -> IntrinsicSize {
2582 self.size
2583 }
2584}
2585
2586impl DelegatableNode for IntrinsicSizeNode {
2587 fn node_state(&self) -> &NodeState {
2588 &self.state
2589 }
2590}
2591
2592impl ModifierNode for IntrinsicSizeNode {
2593 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2594 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2595 }
2596}
2597
2598#[derive(Debug, Clone, PartialEq)]
2600pub struct IntrinsicSizeElement {
2601 axis: IntrinsicAxis,
2602 size: IntrinsicSize,
2603}
2604
2605impl IntrinsicSizeElement {
2606 pub fn width(size: IntrinsicSize) -> Self {
2607 Self {
2608 axis: IntrinsicAxis::Width,
2609 size,
2610 }
2611 }
2612
2613 pub fn height(size: IntrinsicSize) -> Self {
2614 Self {
2615 axis: IntrinsicAxis::Height,
2616 size,
2617 }
2618 }
2619}
2620
2621impl Hash for IntrinsicSizeElement {
2622 fn hash<H: Hasher>(&self, state: &mut H) {
2623 state.write_u8(match self.axis {
2624 IntrinsicAxis::Width => 0,
2625 IntrinsicAxis::Height => 1,
2626 });
2627 state.write_u8(match self.size {
2628 IntrinsicSize::Min => 0,
2629 IntrinsicSize::Max => 1,
2630 });
2631 }
2632}
2633
2634impl ModifierNodeElement for IntrinsicSizeElement {
2635 type Node = IntrinsicSizeNode;
2636
2637 fn create(&self) -> Self::Node {
2638 IntrinsicSizeNode::new(self.axis, self.size)
2639 }
2640
2641 fn update(&self, node: &mut Self::Node) {
2642 if node.axis != self.axis {
2643 node.axis = self.axis;
2644 }
2645 if node.size != self.size {
2646 node.size = self.size;
2647 }
2648 }
2649
2650 fn capabilities(&self) -> NodeCapabilities {
2651 NodeCapabilities::LAYOUT
2652 }
2653}
2654
2655#[cfg(test)]
2656#[path = "tests/modifier_nodes_tests.rs"]
2657mod tests;