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;
72use std::sync::atomic::{AtomicUsize, Ordering};
73
74use crate::draw::DrawCommand;
75use crate::modifier::{
76 BlendMode, Color, ColorFilter, CompositingStrategy, EdgeInsets, GraphicsLayer, LayoutWeight,
77 Point, RoundedCornerShape,
78};
79
80fn hash_f32_value<H: Hasher>(state: &mut H, value: f32) {
81 state.write_u32(value.to_bits());
82}
83
84fn hash_option_f32<H: Hasher>(state: &mut H, value: Option<f32>) {
85 match value {
86 Some(v) => {
87 state.write_u8(1);
88 hash_f32_value(state, v);
89 }
90 None => state.write_u8(0),
91 }
92}
93
94fn hash_graphics_layer<H: Hasher>(state: &mut H, layer: &GraphicsLayer) {
95 hash_f32_value(state, layer.alpha);
96 hash_f32_value(state, layer.scale);
97 hash_f32_value(state, layer.scale_x);
98 hash_f32_value(state, layer.scale_y);
99 hash_f32_value(state, layer.rotation_x);
100 hash_f32_value(state, layer.rotation_y);
101 hash_f32_value(state, layer.rotation_z);
102 hash_f32_value(state, layer.camera_distance);
103 hash_f32_value(state, layer.transform_origin.pivot_fraction_x);
104 hash_f32_value(state, layer.transform_origin.pivot_fraction_y);
105 hash_f32_value(state, layer.translation_x);
106 hash_f32_value(state, layer.translation_y);
107 hash_f32_value(state, layer.shadow_elevation);
108 hash_f32_value(state, layer.ambient_shadow_color.r());
109 hash_f32_value(state, layer.ambient_shadow_color.g());
110 hash_f32_value(state, layer.ambient_shadow_color.b());
111 hash_f32_value(state, layer.ambient_shadow_color.a());
112 hash_f32_value(state, layer.spot_shadow_color.r());
113 hash_f32_value(state, layer.spot_shadow_color.g());
114 hash_f32_value(state, layer.spot_shadow_color.b());
115 hash_f32_value(state, layer.spot_shadow_color.a());
116 match layer.shape {
117 crate::modifier::LayerShape::Rectangle => {
118 state.write_u8(0);
119 }
120 crate::modifier::LayerShape::Rounded(shape) => {
121 state.write_u8(1);
122 let radii = shape.radii();
123 hash_f32_value(state, radii.top_left);
124 hash_f32_value(state, radii.top_right);
125 hash_f32_value(state, radii.bottom_right);
126 hash_f32_value(state, radii.bottom_left);
127 }
128 }
129 state.write_u8(layer.clip as u8);
130 match layer.color_filter {
131 Some(ColorFilter::Tint(color)) => {
132 state.write_u8(1);
133 hash_f32_value(state, color.r());
134 hash_f32_value(state, color.g());
135 hash_f32_value(state, color.b());
136 hash_f32_value(state, color.a());
137 }
138 Some(ColorFilter::Modulate(color)) => {
139 state.write_u8(2);
140 hash_f32_value(state, color.r());
141 hash_f32_value(state, color.g());
142 hash_f32_value(state, color.b());
143 hash_f32_value(state, color.a());
144 }
145 Some(ColorFilter::Matrix(matrix)) => {
146 state.write_u8(3);
147 for value in matrix {
148 hash_f32_value(state, value);
149 }
150 }
151 None => state.write_u8(0),
152 }
153 state.write_u8(layer.render_effect.is_some() as u8);
154 state.write_u8(layer.backdrop_effect.is_some() as u8);
155 let compositing_tag = match layer.compositing_strategy {
156 CompositingStrategy::Auto => 0,
157 CompositingStrategy::Offscreen => 1,
158 CompositingStrategy::ModulateAlpha => 2,
159 };
160 state.write_u8(compositing_tag);
161 let blend_tag = match layer.blend_mode {
162 BlendMode::Clear => 0,
163 BlendMode::Src => 1,
164 BlendMode::Dst => 2,
165 BlendMode::SrcOver => 3,
166 BlendMode::DstOver => 4,
167 BlendMode::SrcIn => 5,
168 BlendMode::DstIn => 6,
169 BlendMode::SrcOut => 7,
170 BlendMode::DstOut => 8,
171 BlendMode::SrcAtop => 9,
172 BlendMode::DstAtop => 10,
173 BlendMode::Xor => 11,
174 BlendMode::Plus => 12,
175 BlendMode::Modulate => 13,
176 BlendMode::Screen => 14,
177 BlendMode::Overlay => 15,
178 BlendMode::Darken => 16,
179 BlendMode::Lighten => 17,
180 BlendMode::ColorDodge => 18,
181 BlendMode::ColorBurn => 19,
182 BlendMode::HardLight => 20,
183 BlendMode::SoftLight => 21,
184 BlendMode::Difference => 22,
185 BlendMode::Exclusion => 23,
186 BlendMode::Multiply => 24,
187 BlendMode::Hue => 25,
188 BlendMode::Saturation => 26,
189 BlendMode::Color => 27,
190 BlendMode::Luminosity => 28,
191 };
192 state.write_u8(blend_tag);
193}
194
195fn hash_horizontal_alignment<H: Hasher>(state: &mut H, alignment: HorizontalAlignment) {
196 let tag = match alignment {
197 HorizontalAlignment::Start => 0,
198 HorizontalAlignment::CenterHorizontally => 1,
199 HorizontalAlignment::End => 2,
200 };
201 state.write_u8(tag);
202}
203
204fn hash_vertical_alignment<H: Hasher>(state: &mut H, alignment: VerticalAlignment) {
205 let tag = match alignment {
206 VerticalAlignment::Top => 0,
207 VerticalAlignment::CenterVertically => 1,
208 VerticalAlignment::Bottom => 2,
209 };
210 state.write_u8(tag);
211}
212
213fn hash_alignment<H: Hasher>(state: &mut H, alignment: Alignment) {
214 hash_horizontal_alignment(state, alignment.horizontal);
215 hash_vertical_alignment(state, alignment.vertical);
216}
217
218static NEXT_LAZY_GRAPHICS_LAYER_SCOPE_ID: AtomicUsize = AtomicUsize::new(1);
219
220fn next_lazy_graphics_layer_scope_id() -> usize {
221 NEXT_LAZY_GRAPHICS_LAYER_SCOPE_ID.fetch_add(1, Ordering::Relaxed)
222}
223
224#[derive(Debug)]
230pub struct PaddingNode {
231 padding: EdgeInsets,
232 state: NodeState,
233}
234
235impl PaddingNode {
236 pub fn new(padding: EdgeInsets) -> Self {
237 Self {
238 padding,
239 state: NodeState::new(),
240 }
241 }
242
243 pub fn padding(&self) -> EdgeInsets {
244 self.padding
245 }
246}
247
248impl DelegatableNode for PaddingNode {
249 fn node_state(&self) -> &NodeState {
250 &self.state
251 }
252}
253
254impl ModifierNode for PaddingNode {
255 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
256 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
257 }
258
259 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
260 Some(self)
261 }
262
263 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
264 Some(self)
265 }
266}
267
268impl LayoutModifierNode for PaddingNode {
269 fn measure(
270 &self,
271 _context: &mut dyn ModifierNodeContext,
272 measurable: &dyn Measurable,
273 constraints: Constraints,
274 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
275 let horizontal_padding = self.padding.horizontal_sum();
277 let vertical_padding = self.padding.vertical_sum();
278
279 let inner_constraints = Constraints {
281 min_width: (constraints.min_width - horizontal_padding).max(0.0),
282 max_width: (constraints.max_width - horizontal_padding).max(0.0),
283 min_height: (constraints.min_height - vertical_padding).max(0.0),
284 max_height: (constraints.max_height - vertical_padding).max(0.0),
285 };
286
287 let inner_placeable = measurable.measure(inner_constraints);
289 let inner_width = inner_placeable.width();
290 let inner_height = inner_placeable.height();
291
292 let (width, height) = constraints.constrain(
293 inner_width + horizontal_padding,
294 inner_height + vertical_padding,
295 );
296
297 cranpose_ui_layout::LayoutModifierMeasureResult::new(
299 Size { width, height },
300 self.padding.left, self.padding.top, )
303 }
304
305 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
306 let vertical_padding = self.padding.vertical_sum();
307 let inner_height = (height - vertical_padding).max(0.0);
308 let inner_width = measurable.min_intrinsic_width(inner_height);
309 inner_width + self.padding.horizontal_sum()
310 }
311
312 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
313 let vertical_padding = self.padding.vertical_sum();
314 let inner_height = (height - vertical_padding).max(0.0);
315 let inner_width = measurable.max_intrinsic_width(inner_height);
316 inner_width + self.padding.horizontal_sum()
317 }
318
319 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
320 let horizontal_padding = self.padding.horizontal_sum();
321 let inner_width = (width - horizontal_padding).max(0.0);
322 let inner_height = measurable.min_intrinsic_height(inner_width);
323 inner_height + self.padding.vertical_sum()
324 }
325
326 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
327 let horizontal_padding = self.padding.horizontal_sum();
328 let inner_width = (width - horizontal_padding).max(0.0);
329 let inner_height = measurable.max_intrinsic_height(inner_width);
330 inner_height + self.padding.vertical_sum()
331 }
332
333 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
334 Some(Box::new(PaddingMeasurementProxy {
335 padding: self.padding,
336 }))
337 }
338}
339
340struct PaddingMeasurementProxy {
346 padding: EdgeInsets,
347}
348
349impl MeasurementProxy for PaddingMeasurementProxy {
350 fn measure_proxy(
351 &self,
352 _context: &mut dyn ModifierNodeContext,
353 wrapped: &dyn Measurable,
354 constraints: Constraints,
355 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
356 let horizontal_padding = self.padding.horizontal_sum();
358 let vertical_padding = self.padding.vertical_sum();
359
360 let inner_constraints = Constraints {
362 min_width: (constraints.min_width - horizontal_padding).max(0.0),
363 max_width: (constraints.max_width - horizontal_padding).max(0.0),
364 min_height: (constraints.min_height - vertical_padding).max(0.0),
365 max_height: (constraints.max_height - vertical_padding).max(0.0),
366 };
367
368 let inner_placeable = wrapped.measure(inner_constraints);
370 let inner_width = inner_placeable.width();
371 let inner_height = inner_placeable.height();
372
373 let (width, height) = constraints.constrain(
374 inner_width + horizontal_padding,
375 inner_height + vertical_padding,
376 );
377
378 cranpose_ui_layout::LayoutModifierMeasureResult::new(
380 Size { width, height },
381 self.padding.left, self.padding.top, )
384 }
385
386 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
387 let vertical_padding = self.padding.vertical_sum();
388 let inner_height = (height - vertical_padding).max(0.0);
389 let inner_width = wrapped.min_intrinsic_width(inner_height);
390 inner_width + self.padding.horizontal_sum()
391 }
392
393 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
394 let vertical_padding = self.padding.vertical_sum();
395 let inner_height = (height - vertical_padding).max(0.0);
396 let inner_width = wrapped.max_intrinsic_width(inner_height);
397 inner_width + self.padding.horizontal_sum()
398 }
399
400 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
401 let horizontal_padding = self.padding.horizontal_sum();
402 let inner_width = (width - horizontal_padding).max(0.0);
403 let inner_height = wrapped.min_intrinsic_height(inner_width);
404 inner_height + self.padding.vertical_sum()
405 }
406
407 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
408 let horizontal_padding = self.padding.horizontal_sum();
409 let inner_width = (width - horizontal_padding).max(0.0);
410 let inner_height = wrapped.max_intrinsic_height(inner_width);
411 inner_height + self.padding.vertical_sum()
412 }
413}
414
415#[derive(Debug, Clone, PartialEq)]
417pub struct PaddingElement {
418 padding: EdgeInsets,
419}
420
421impl PaddingElement {
422 pub fn new(padding: EdgeInsets) -> Self {
423 Self { padding }
424 }
425}
426
427impl Hash for PaddingElement {
428 fn hash<H: Hasher>(&self, state: &mut H) {
429 hash_f32_value(state, self.padding.left);
430 hash_f32_value(state, self.padding.top);
431 hash_f32_value(state, self.padding.right);
432 hash_f32_value(state, self.padding.bottom);
433 }
434}
435
436impl ModifierNodeElement for PaddingElement {
437 type Node = PaddingNode;
438
439 fn create(&self) -> Self::Node {
440 PaddingNode::new(self.padding)
441 }
442
443 fn update(&self, node: &mut Self::Node) {
444 if node.padding != self.padding {
445 node.padding = self.padding;
446 }
448 }
449
450 fn capabilities(&self) -> NodeCapabilities {
451 NodeCapabilities::LAYOUT
452 }
453}
454
455#[derive(Debug)]
461pub struct BackgroundNode {
462 color: Color,
463 shape: Option<RoundedCornerShape>,
464 state: NodeState,
465}
466
467impl BackgroundNode {
468 pub fn new(color: Color) -> Self {
469 Self {
470 color,
471 shape: None,
472 state: NodeState::new(),
473 }
474 }
475
476 pub fn color(&self) -> Color {
477 self.color
478 }
479
480 pub fn shape(&self) -> Option<RoundedCornerShape> {
481 self.shape
482 }
483}
484
485impl DelegatableNode for BackgroundNode {
486 fn node_state(&self) -> &NodeState {
487 &self.state
488 }
489}
490
491impl ModifierNode for BackgroundNode {
492 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
493 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
494 }
495
496 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
497 Some(self)
498 }
499
500 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
501 Some(self)
502 }
503}
504
505impl DrawModifierNode for BackgroundNode {
506 fn draw(&self, _draw_scope: &mut dyn DrawScope) {
507 }
510}
511
512#[derive(Debug, Clone, PartialEq)]
514pub struct BackgroundElement {
515 color: Color,
516}
517
518impl BackgroundElement {
519 pub fn new(color: Color) -> Self {
520 Self { color }
521 }
522}
523
524impl Hash for BackgroundElement {
525 fn hash<H: Hasher>(&self, state: &mut H) {
526 hash_f32_value(state, self.color.0);
527 hash_f32_value(state, self.color.1);
528 hash_f32_value(state, self.color.2);
529 hash_f32_value(state, self.color.3);
530 }
531}
532
533impl ModifierNodeElement for BackgroundElement {
534 type Node = BackgroundNode;
535
536 fn create(&self) -> Self::Node {
537 BackgroundNode::new(self.color)
538 }
539
540 fn update(&self, node: &mut Self::Node) {
541 if node.color != self.color {
542 node.color = self.color;
543 }
545 }
546
547 fn capabilities(&self) -> NodeCapabilities {
548 NodeCapabilities::DRAW
549 }
550}
551
552#[derive(Debug)]
558pub struct CornerShapeNode {
559 shape: RoundedCornerShape,
560 state: NodeState,
561}
562
563impl CornerShapeNode {
564 pub fn new(shape: RoundedCornerShape) -> Self {
565 Self {
566 shape,
567 state: NodeState::new(),
568 }
569 }
570
571 pub fn shape(&self) -> RoundedCornerShape {
572 self.shape
573 }
574}
575
576impl DelegatableNode for CornerShapeNode {
577 fn node_state(&self) -> &NodeState {
578 &self.state
579 }
580}
581
582impl ModifierNode for CornerShapeNode {
583 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
584 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
585 }
586
587 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
588 Some(self)
589 }
590
591 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
592 Some(self)
593 }
594}
595
596impl DrawModifierNode for CornerShapeNode {
597 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
598}
599
600#[derive(Debug, Clone, PartialEq)]
602pub struct CornerShapeElement {
603 shape: RoundedCornerShape,
604}
605
606impl CornerShapeElement {
607 pub fn new(shape: RoundedCornerShape) -> Self {
608 Self { shape }
609 }
610}
611
612impl Hash for CornerShapeElement {
613 fn hash<H: Hasher>(&self, state: &mut H) {
614 let radii = self.shape.radii();
615 hash_f32_value(state, radii.top_left);
616 hash_f32_value(state, radii.top_right);
617 hash_f32_value(state, radii.bottom_right);
618 hash_f32_value(state, radii.bottom_left);
619 }
620}
621
622impl ModifierNodeElement for CornerShapeElement {
623 type Node = CornerShapeNode;
624
625 fn create(&self) -> Self::Node {
626 CornerShapeNode::new(self.shape)
627 }
628
629 fn update(&self, node: &mut Self::Node) {
630 if node.shape != self.shape {
631 node.shape = self.shape;
632 }
634 }
635
636 fn capabilities(&self) -> NodeCapabilities {
637 NodeCapabilities::DRAW
638 }
639}
640
641pub struct GraphicsLayerNode {
647 layer: GraphicsLayer,
648 layer_resolver: Option<Rc<dyn Fn() -> GraphicsLayer>>,
649 lazy_scope_id: Option<usize>,
650 lazy_observer: Option<cranpose_core::SnapshotStateObserver>,
651 state: NodeState,
652}
653
654impl GraphicsLayerNode {
655 pub fn new(layer: GraphicsLayer) -> Self {
656 Self {
657 layer,
658 layer_resolver: None,
659 lazy_scope_id: None,
660 lazy_observer: None,
661 state: NodeState::new(),
662 }
663 }
664
665 pub fn new_lazy(layer_resolver: Rc<dyn Fn() -> GraphicsLayer>) -> Self {
666 let mut node = Self {
667 layer: GraphicsLayer::default(),
668 layer_resolver: Some(layer_resolver),
669 lazy_scope_id: None,
670 lazy_observer: None,
671 state: NodeState::new(),
672 };
673 node.ensure_lazy_observation();
674 node.layer = node.layer();
675 node
676 }
677
678 pub fn layer(&self) -> GraphicsLayer {
679 if let Some(resolve) = self.layer_resolver() {
680 resolve()
681 } else {
682 self.layer.clone()
683 }
684 }
685
686 pub fn layer_snapshot(&self) -> GraphicsLayer {
687 self.layer.clone()
688 }
689
690 pub fn layer_resolver(&self) -> Option<Rc<dyn Fn() -> GraphicsLayer>> {
691 self.layer_resolver.as_ref().map(|resolve| {
692 let resolve = resolve.clone();
693 match (&self.lazy_observer, self.lazy_scope_id) {
694 (Some(observer), Some(scope_id)) => {
695 let observer = observer.clone();
696 Rc::new(move || {
697 observer.observe_reads(
698 scope_id,
699 |_| crate::request_render_invalidation(),
700 || resolve(),
701 )
702 }) as Rc<dyn Fn() -> GraphicsLayer>
703 }
704 _ => resolve,
705 }
706 })
707 }
708
709 fn set_static(&mut self, layer: GraphicsLayer) {
710 self.layer = layer;
711 self.layer_resolver = None;
712 self.clear_lazy_observation();
713 }
714
715 fn set_lazy(&mut self, layer_resolver: Rc<dyn Fn() -> GraphicsLayer>) {
716 self.layer_resolver = Some(layer_resolver);
717 self.ensure_lazy_observation();
718 self.layer = self.layer();
719 }
720
721 fn ensure_lazy_observation(&mut self) {
722 if self.layer_resolver.is_none() {
723 self.clear_lazy_observation();
724 return;
725 }
726 if self.lazy_observer.is_some() {
727 return;
728 }
729 let observer = cranpose_core::SnapshotStateObserver::new(|callback| callback());
730 observer.start();
731 self.lazy_scope_id = Some(next_lazy_graphics_layer_scope_id());
732 self.lazy_observer = Some(observer);
733 }
734
735 fn clear_lazy_observation(&mut self) {
736 if let Some(observer) = self.lazy_observer.take() {
737 observer.stop();
738 }
739 self.lazy_scope_id = None;
740 }
741}
742
743impl DelegatableNode for GraphicsLayerNode {
744 fn node_state(&self) -> &NodeState {
745 &self.state
746 }
747}
748
749impl ModifierNode for GraphicsLayerNode {
750 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
751 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
752 }
753
754 fn on_detach(&mut self) {
755 self.clear_lazy_observation();
756 }
757}
758
759impl std::fmt::Debug for GraphicsLayerNode {
760 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
761 f.debug_struct("GraphicsLayerNode")
762 .field("layer", &self.layer)
763 .field("lazy", &self.layer_resolver.is_some())
764 .finish()
765 }
766}
767
768#[derive(Debug, Clone, PartialEq)]
770pub struct GraphicsLayerElement {
771 layer: GraphicsLayer,
772}
773
774impl GraphicsLayerElement {
775 pub fn new(layer: GraphicsLayer) -> Self {
776 Self { layer }
777 }
778}
779
780impl Hash for GraphicsLayerElement {
781 fn hash<H: Hasher>(&self, state: &mut H) {
782 hash_graphics_layer(state, &self.layer);
783 }
784}
785
786impl ModifierNodeElement for GraphicsLayerElement {
787 type Node = GraphicsLayerNode;
788
789 fn create(&self) -> Self::Node {
790 GraphicsLayerNode::new(self.layer.clone())
791 }
792
793 fn update(&self, node: &mut Self::Node) {
794 node.set_static(self.layer.clone());
795 }
796
797 fn capabilities(&self) -> NodeCapabilities {
798 NodeCapabilities::DRAW
799 }
800}
801
802#[derive(Clone)]
804pub struct LazyGraphicsLayerElement {
805 layer_resolver: Rc<dyn Fn() -> GraphicsLayer>,
806}
807
808impl LazyGraphicsLayerElement {
809 pub fn new(layer_resolver: Rc<dyn Fn() -> GraphicsLayer>) -> Self {
810 Self { layer_resolver }
811 }
812}
813
814impl std::fmt::Debug for LazyGraphicsLayerElement {
815 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
816 f.debug_struct("LazyGraphicsLayerElement")
817 .field("resolver", &"<closure>")
818 .finish()
819 }
820}
821
822impl PartialEq for LazyGraphicsLayerElement {
823 fn eq(&self, other: &Self) -> bool {
824 Rc::ptr_eq(&self.layer_resolver, &other.layer_resolver)
825 }
826}
827
828impl Eq for LazyGraphicsLayerElement {}
829
830impl Hash for LazyGraphicsLayerElement {
831 fn hash<H: Hasher>(&self, state: &mut H) {
832 let ptr = Rc::as_ptr(&self.layer_resolver) as *const ();
833 ptr.hash(state);
834 }
835}
836
837impl ModifierNodeElement for LazyGraphicsLayerElement {
838 type Node = GraphicsLayerNode;
839
840 fn create(&self) -> Self::Node {
841 GraphicsLayerNode::new_lazy(self.layer_resolver.clone())
842 }
843
844 fn update(&self, node: &mut Self::Node) {
845 node.set_lazy(self.layer_resolver.clone());
846 }
847
848 fn capabilities(&self) -> NodeCapabilities {
849 NodeCapabilities::DRAW
850 }
851
852 fn always_update(&self) -> bool {
853 true
854 }
855}
856
857#[derive(Debug)]
865pub struct SizeNode {
866 min_width: Option<f32>,
867 max_width: Option<f32>,
868 min_height: Option<f32>,
869 max_height: Option<f32>,
870 enforce_incoming: bool,
871 state: NodeState,
872}
873
874impl SizeNode {
875 pub fn new(
876 min_width: Option<f32>,
877 max_width: Option<f32>,
878 min_height: Option<f32>,
879 max_height: Option<f32>,
880 enforce_incoming: bool,
881 ) -> Self {
882 Self {
883 min_width,
884 max_width,
885 min_height,
886 max_height,
887 enforce_incoming,
888 state: NodeState::new(),
889 }
890 }
891
892 fn target_constraints(&self) -> Constraints {
894 let max_width = self.max_width.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
895 let max_height = self.max_height.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
896
897 let min_width = self
898 .min_width
899 .map(|v| {
900 let clamped = v.clamp(0.0, max_width);
901 if clamped == f32::INFINITY {
902 0.0
903 } else {
904 clamped
905 }
906 })
907 .unwrap_or(0.0);
908
909 let min_height = self
910 .min_height
911 .map(|v| {
912 let clamped = v.clamp(0.0, max_height);
913 if clamped == f32::INFINITY {
914 0.0
915 } else {
916 clamped
917 }
918 })
919 .unwrap_or(0.0);
920
921 Constraints {
922 min_width,
923 max_width,
924 min_height,
925 max_height,
926 }
927 }
928
929 pub fn min_width(&self) -> Option<f32> {
930 self.min_width
931 }
932
933 pub fn max_width(&self) -> Option<f32> {
934 self.max_width
935 }
936
937 pub fn min_height(&self) -> Option<f32> {
938 self.min_height
939 }
940
941 pub fn max_height(&self) -> Option<f32> {
942 self.max_height
943 }
944
945 pub fn enforce_incoming(&self) -> bool {
946 self.enforce_incoming
947 }
948}
949
950impl DelegatableNode for SizeNode {
951 fn node_state(&self) -> &NodeState {
952 &self.state
953 }
954}
955
956impl ModifierNode for SizeNode {
957 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
958 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
959 }
960
961 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
962 Some(self)
963 }
964
965 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
966 Some(self)
967 }
968}
969
970impl LayoutModifierNode for SizeNode {
971 fn measure(
972 &self,
973 _context: &mut dyn ModifierNodeContext,
974 measurable: &dyn Measurable,
975 constraints: Constraints,
976 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
977 let target = self.target_constraints();
978
979 let wrapped_constraints = if self.enforce_incoming {
980 Constraints {
982 min_width: target
983 .min_width
984 .max(constraints.min_width)
985 .min(constraints.max_width),
986 max_width: target
987 .max_width
988 .min(constraints.max_width)
989 .max(constraints.min_width),
990 min_height: target
991 .min_height
992 .max(constraints.min_height)
993 .min(constraints.max_height),
994 max_height: target
995 .max_height
996 .min(constraints.max_height)
997 .max(constraints.min_height),
998 }
999 } else {
1000 let resolved_min_width = if self.min_width.is_some() {
1002 target.min_width
1003 } else {
1004 constraints.min_width.min(target.max_width)
1005 };
1006 let resolved_max_width = if self.max_width.is_some() {
1007 target.max_width
1008 } else {
1009 constraints.max_width.max(target.min_width)
1010 };
1011 let resolved_min_height = if self.min_height.is_some() {
1012 target.min_height
1013 } else {
1014 constraints.min_height.min(target.max_height)
1015 };
1016 let resolved_max_height = if self.max_height.is_some() {
1017 target.max_height
1018 } else {
1019 constraints.max_height.max(target.min_height)
1020 };
1021
1022 Constraints {
1023 min_width: resolved_min_width,
1024 max_width: resolved_max_width,
1025 min_height: resolved_min_height,
1026 max_height: resolved_max_height,
1027 }
1028 };
1029
1030 let placeable = measurable.measure(wrapped_constraints);
1031 let measured_width = placeable.width();
1032 let measured_height = placeable.height();
1033
1034 let result_width = if self.min_width.is_some()
1038 && self.max_width.is_some()
1039 && self.min_width == self.max_width
1040 && target.min_width >= wrapped_constraints.min_width
1041 && target.min_width <= wrapped_constraints.max_width
1042 {
1043 target.min_width
1044 } else {
1045 measured_width
1046 };
1047
1048 let result_height = if self.min_height.is_some()
1049 && self.max_height.is_some()
1050 && self.min_height == self.max_height
1051 && target.min_height >= wrapped_constraints.min_height
1052 && target.min_height <= wrapped_constraints.max_height
1053 {
1054 target.min_height
1055 } else {
1056 measured_height
1057 };
1058
1059 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
1061 width: result_width,
1062 height: result_height,
1063 })
1064 }
1065
1066 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
1067 let target = self.target_constraints();
1068 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1069 target.max_width
1070 } else {
1071 let child_height = if self.enforce_incoming {
1072 height
1073 } else {
1074 height.clamp(target.min_height, target.max_height)
1075 };
1076 measurable
1077 .min_intrinsic_width(child_height)
1078 .clamp(target.min_width, target.max_width)
1079 }
1080 }
1081
1082 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
1083 let target = self.target_constraints();
1084 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1085 target.max_width
1086 } else {
1087 let child_height = if self.enforce_incoming {
1088 height
1089 } else {
1090 height.clamp(target.min_height, target.max_height)
1091 };
1092 measurable
1093 .max_intrinsic_width(child_height)
1094 .clamp(target.min_width, target.max_width)
1095 }
1096 }
1097
1098 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
1099 let target = self.target_constraints();
1100 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1101 target.max_height
1102 } else {
1103 let child_width = if self.enforce_incoming {
1104 width
1105 } else {
1106 width.clamp(target.min_width, target.max_width)
1107 };
1108 measurable
1109 .min_intrinsic_height(child_width)
1110 .clamp(target.min_height, target.max_height)
1111 }
1112 }
1113
1114 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
1115 let target = self.target_constraints();
1116 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1117 target.max_height
1118 } else {
1119 let child_width = if self.enforce_incoming {
1120 width
1121 } else {
1122 width.clamp(target.min_width, target.max_width)
1123 };
1124 measurable
1125 .max_intrinsic_height(child_width)
1126 .clamp(target.min_height, target.max_height)
1127 }
1128 }
1129
1130 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
1131 Some(Box::new(SizeMeasurementProxy {
1132 min_width: self.min_width,
1133 max_width: self.max_width,
1134 min_height: self.min_height,
1135 max_height: self.max_height,
1136 enforce_incoming: self.enforce_incoming,
1137 }))
1138 }
1139}
1140
1141struct SizeMeasurementProxy {
1146 min_width: Option<f32>,
1147 max_width: Option<f32>,
1148 min_height: Option<f32>,
1149 max_height: Option<f32>,
1150 enforce_incoming: bool,
1151}
1152
1153impl SizeMeasurementProxy {
1154 fn target_constraints(&self) -> Constraints {
1157 let max_width = self.max_width.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
1158 let max_height = self.max_height.map(|v| v.max(0.0)).unwrap_or(f32::INFINITY);
1159
1160 let min_width = self
1161 .min_width
1162 .map(|v| {
1163 let clamped = v.clamp(0.0, max_width);
1164 if clamped == f32::INFINITY {
1165 0.0
1166 } else {
1167 clamped
1168 }
1169 })
1170 .unwrap_or(0.0);
1171
1172 let min_height = self
1173 .min_height
1174 .map(|v| {
1175 let clamped = v.clamp(0.0, max_height);
1176 if clamped == f32::INFINITY {
1177 0.0
1178 } else {
1179 clamped
1180 }
1181 })
1182 .unwrap_or(0.0);
1183
1184 Constraints {
1185 min_width,
1186 max_width,
1187 min_height,
1188 max_height,
1189 }
1190 }
1191}
1192
1193impl MeasurementProxy for SizeMeasurementProxy {
1194 fn measure_proxy(
1195 &self,
1196 _context: &mut dyn ModifierNodeContext,
1197 wrapped: &dyn Measurable,
1198 constraints: Constraints,
1199 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
1200 let target = self.target_constraints();
1202
1203 let wrapped_constraints = if self.enforce_incoming {
1204 Constraints {
1206 min_width: target
1207 .min_width
1208 .max(constraints.min_width)
1209 .min(constraints.max_width),
1210 max_width: target
1211 .max_width
1212 .min(constraints.max_width)
1213 .max(constraints.min_width),
1214 min_height: target
1215 .min_height
1216 .max(constraints.min_height)
1217 .min(constraints.max_height),
1218 max_height: target
1219 .max_height
1220 .min(constraints.max_height)
1221 .max(constraints.min_height),
1222 }
1223 } else {
1224 let resolved_min_width = if self.min_width.is_some() {
1226 target.min_width
1227 } else {
1228 constraints.min_width.min(target.max_width)
1229 };
1230 let resolved_max_width = if self.max_width.is_some() {
1231 target.max_width
1232 } else {
1233 constraints.max_width.max(target.min_width)
1234 };
1235 let resolved_min_height = if self.min_height.is_some() {
1236 target.min_height
1237 } else {
1238 constraints.min_height.min(target.max_height)
1239 };
1240 let resolved_max_height = if self.max_height.is_some() {
1241 target.max_height
1242 } else {
1243 constraints.max_height.max(target.min_height)
1244 };
1245
1246 Constraints {
1247 min_width: resolved_min_width,
1248 max_width: resolved_max_width,
1249 min_height: resolved_min_height,
1250 max_height: resolved_max_height,
1251 }
1252 };
1253
1254 let placeable = wrapped.measure(wrapped_constraints);
1255 let measured_width = placeable.width();
1256 let measured_height = placeable.height();
1257
1258 let result_width = if self.min_width.is_some()
1261 && self.max_width.is_some()
1262 && self.min_width == self.max_width
1263 && target.min_width >= wrapped_constraints.min_width
1264 && target.min_width <= wrapped_constraints.max_width
1265 {
1266 target.min_width
1267 } else {
1268 measured_width
1269 };
1270
1271 let result_height = if self.min_height.is_some()
1272 && self.max_height.is_some()
1273 && self.min_height == self.max_height
1274 && target.min_height >= wrapped_constraints.min_height
1275 && target.min_height <= wrapped_constraints.max_height
1276 {
1277 target.min_height
1278 } else {
1279 measured_height
1280 };
1281
1282 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
1284 width: result_width,
1285 height: result_height,
1286 })
1287 }
1288
1289 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1290 let target = self.target_constraints();
1291 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1292 target.max_width
1293 } else {
1294 let child_height = if self.enforce_incoming {
1295 height
1296 } else {
1297 height.clamp(target.min_height, target.max_height)
1298 };
1299 wrapped
1300 .min_intrinsic_width(child_height)
1301 .clamp(target.min_width, target.max_width)
1302 }
1303 }
1304
1305 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
1306 let target = self.target_constraints();
1307 if target.min_width == target.max_width && target.max_width != f32::INFINITY {
1308 target.max_width
1309 } else {
1310 let child_height = if self.enforce_incoming {
1311 height
1312 } else {
1313 height.clamp(target.min_height, target.max_height)
1314 };
1315 wrapped
1316 .max_intrinsic_width(child_height)
1317 .clamp(target.min_width, target.max_width)
1318 }
1319 }
1320
1321 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1322 let target = self.target_constraints();
1323 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1324 target.max_height
1325 } else {
1326 let child_width = if self.enforce_incoming {
1327 width
1328 } else {
1329 width.clamp(target.min_width, target.max_width)
1330 };
1331 wrapped
1332 .min_intrinsic_height(child_width)
1333 .clamp(target.min_height, target.max_height)
1334 }
1335 }
1336
1337 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
1338 let target = self.target_constraints();
1339 if target.min_height == target.max_height && target.max_height != f32::INFINITY {
1340 target.max_height
1341 } else {
1342 let child_width = if self.enforce_incoming {
1343 width
1344 } else {
1345 width.clamp(target.min_width, target.max_width)
1346 };
1347 wrapped
1348 .max_intrinsic_height(child_width)
1349 .clamp(target.min_height, target.max_height)
1350 }
1351 }
1352}
1353
1354#[derive(Debug, Clone, PartialEq)]
1358pub struct SizeElement {
1359 min_width: Option<f32>,
1360 max_width: Option<f32>,
1361 min_height: Option<f32>,
1362 max_height: Option<f32>,
1363 enforce_incoming: bool,
1364}
1365
1366impl SizeElement {
1367 pub fn new(width: Option<f32>, height: Option<f32>) -> Self {
1368 Self {
1369 min_width: width,
1370 max_width: width,
1371 min_height: height,
1372 max_height: height,
1373 enforce_incoming: true,
1374 }
1375 }
1376
1377 pub fn with_constraints(
1378 min_width: Option<f32>,
1379 max_width: Option<f32>,
1380 min_height: Option<f32>,
1381 max_height: Option<f32>,
1382 enforce_incoming: bool,
1383 ) -> Self {
1384 Self {
1385 min_width,
1386 max_width,
1387 min_height,
1388 max_height,
1389 enforce_incoming,
1390 }
1391 }
1392}
1393
1394impl Hash for SizeElement {
1395 fn hash<H: Hasher>(&self, state: &mut H) {
1396 hash_option_f32(state, self.min_width);
1397 hash_option_f32(state, self.max_width);
1398 hash_option_f32(state, self.min_height);
1399 hash_option_f32(state, self.max_height);
1400 self.enforce_incoming.hash(state);
1401 }
1402}
1403
1404impl ModifierNodeElement for SizeElement {
1405 type Node = SizeNode;
1406
1407 fn create(&self) -> Self::Node {
1408 SizeNode::new(
1409 self.min_width,
1410 self.max_width,
1411 self.min_height,
1412 self.max_height,
1413 self.enforce_incoming,
1414 )
1415 }
1416
1417 fn update(&self, node: &mut Self::Node) {
1418 if node.min_width != self.min_width
1419 || node.max_width != self.max_width
1420 || node.min_height != self.min_height
1421 || node.max_height != self.max_height
1422 || node.enforce_incoming != self.enforce_incoming
1423 {
1424 node.min_width = self.min_width;
1425 node.max_width = self.max_width;
1426 node.min_height = self.min_height;
1427 node.max_height = self.max_height;
1428 node.enforce_incoming = self.enforce_incoming;
1429 }
1430 }
1431
1432 fn capabilities(&self) -> NodeCapabilities {
1433 NodeCapabilities::LAYOUT
1434 }
1435}
1436
1437use cranpose_foundation::DRAG_THRESHOLD;
1444
1445use std::cell::RefCell;
1446
1447pub struct ClickableNode {
1452 on_click: Rc<dyn Fn(Point)>,
1453 state: NodeState,
1454 press_position: Rc<RefCell<Option<Point>>>,
1456 cached_handler: Rc<dyn Fn(PointerEvent)>,
1458}
1459
1460impl std::fmt::Debug for ClickableNode {
1461 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1462 f.debug_struct("ClickableNode").finish()
1463 }
1464}
1465
1466impl ClickableNode {
1467 pub fn new(on_click: impl Fn(Point) + 'static) -> Self {
1468 Self::with_handler(Rc::new(on_click))
1469 }
1470
1471 pub fn with_handler(on_click: Rc<dyn Fn(Point)>) -> Self {
1472 let press_position = Rc::new(RefCell::new(None));
1473 let cached_handler = Self::create_handler(on_click.clone(), press_position.clone());
1474 Self {
1475 on_click,
1476 state: NodeState::new(),
1477 press_position,
1478 cached_handler,
1479 }
1480 }
1481
1482 fn create_handler(
1483 handler: Rc<dyn Fn(Point)>,
1484 press_position: Rc<RefCell<Option<Point>>>,
1485 ) -> Rc<dyn Fn(PointerEvent)> {
1486 Rc::new(move |event: PointerEvent| {
1487 if event.is_consumed() {
1489 *press_position.borrow_mut() = None;
1491 return;
1492 }
1493
1494 match event.kind {
1495 PointerEventKind::Down => {
1496 *press_position.borrow_mut() = Some(Point {
1498 x: event.global_position.x,
1499 y: event.global_position.y,
1500 });
1501 }
1502 PointerEventKind::Move => {
1503 }
1505 PointerEventKind::Up => {
1506 let press_pos_value = *press_position.borrow();
1508
1509 let should_click = if let Some(press_pos) = press_pos_value {
1510 let dx = event.global_position.x - press_pos.x;
1511 let dy = event.global_position.y - press_pos.y;
1512 let distance = (dx * dx + dy * dy).sqrt();
1513 distance <= DRAG_THRESHOLD
1514 } else {
1515 true
1519 };
1520
1521 *press_position.borrow_mut() = None;
1523
1524 if should_click {
1525 handler(Point {
1526 x: event.position.x,
1527 y: event.position.y,
1528 });
1529 event.consume();
1530 }
1531 }
1532 PointerEventKind::Cancel => {
1533 *press_position.borrow_mut() = None;
1535 }
1536 PointerEventKind::Scroll | PointerEventKind::Enter | PointerEventKind::Exit => {
1537 }
1539 }
1540 })
1541 }
1542
1543 pub fn handler(&self) -> Rc<dyn Fn(Point)> {
1544 self.on_click.clone()
1545 }
1546}
1547
1548impl DelegatableNode for ClickableNode {
1549 fn node_state(&self) -> &NodeState {
1550 &self.state
1551 }
1552}
1553
1554impl ModifierNode for ClickableNode {
1555 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1556 context.invalidate(cranpose_foundation::InvalidationKind::PointerInput);
1557 }
1558
1559 fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
1560 Some(self)
1561 }
1562
1563 fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
1564 Some(self)
1565 }
1566}
1567
1568impl PointerInputNode for ClickableNode {
1569 fn on_pointer_event(
1570 &mut self,
1571 _context: &mut dyn ModifierNodeContext,
1572 event: &PointerEvent,
1573 ) -> bool {
1574 (self.cached_handler)(event.clone());
1577 event.is_consumed()
1578 }
1579
1580 fn hit_test(&self, _x: f32, _y: f32) -> bool {
1581 true
1583 }
1584
1585 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
1586 Some(self.cached_handler.clone())
1589 }
1590}
1591
1592#[derive(Clone)]
1594pub struct ClickableElement {
1595 on_click: Rc<dyn Fn(Point)>,
1596}
1597
1598impl ClickableElement {
1599 pub fn new(on_click: impl Fn(Point) + 'static) -> Self {
1600 Self {
1601 on_click: Rc::new(on_click),
1602 }
1603 }
1604
1605 pub fn with_handler(on_click: Rc<dyn Fn(Point)>) -> Self {
1606 Self { on_click }
1607 }
1608}
1609
1610impl std::fmt::Debug for ClickableElement {
1611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1612 f.debug_struct("ClickableElement").finish()
1613 }
1614}
1615
1616impl PartialEq for ClickableElement {
1617 fn eq(&self, _other: &Self) -> bool {
1618 true
1622 }
1623}
1624
1625impl Eq for ClickableElement {}
1626
1627impl Hash for ClickableElement {
1628 fn hash<H: Hasher>(&self, state: &mut H) {
1629 "clickable".hash(state);
1631 }
1632}
1633
1634impl ModifierNodeElement for ClickableElement {
1635 type Node = ClickableNode;
1636
1637 fn create(&self) -> Self::Node {
1638 ClickableNode::with_handler(self.on_click.clone())
1639 }
1640
1641 fn update(&self, node: &mut Self::Node) {
1647 node.on_click = self.on_click.clone();
1650 node.cached_handler =
1652 ClickableNode::create_handler(node.on_click.clone(), node.press_position.clone());
1653 }
1654
1655 fn capabilities(&self) -> NodeCapabilities {
1656 NodeCapabilities::POINTER_INPUT
1657 }
1658
1659 fn always_update(&self) -> bool {
1660 true
1662 }
1663}
1664
1665#[derive(Debug)]
1671pub struct AlphaNode {
1672 alpha: f32,
1673 state: NodeState,
1674}
1675
1676impl AlphaNode {
1677 pub fn new(alpha: f32) -> Self {
1678 Self {
1679 alpha: alpha.clamp(0.0, 1.0),
1680 state: NodeState::new(),
1681 }
1682 }
1683}
1684
1685impl DelegatableNode for AlphaNode {
1686 fn node_state(&self) -> &NodeState {
1687 &self.state
1688 }
1689}
1690
1691impl ModifierNode for AlphaNode {
1692 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1693 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1694 }
1695
1696 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1697 Some(self)
1698 }
1699
1700 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1701 Some(self)
1702 }
1703}
1704
1705impl DrawModifierNode for AlphaNode {
1706 fn draw(&self, _draw_scope: &mut dyn DrawScope) {
1707 }
1715}
1716
1717#[derive(Debug, Clone, PartialEq)]
1719pub struct AlphaElement {
1720 alpha: f32,
1721}
1722
1723impl AlphaElement {
1724 pub fn new(alpha: f32) -> Self {
1725 Self {
1726 alpha: alpha.clamp(0.0, 1.0),
1727 }
1728 }
1729}
1730
1731impl Hash for AlphaElement {
1732 fn hash<H: Hasher>(&self, state: &mut H) {
1733 hash_f32_value(state, self.alpha);
1734 }
1735}
1736
1737impl ModifierNodeElement for AlphaElement {
1738 type Node = AlphaNode;
1739
1740 fn create(&self) -> Self::Node {
1741 AlphaNode::new(self.alpha)
1742 }
1743
1744 fn update(&self, node: &mut Self::Node) {
1745 let new_alpha = self.alpha.clamp(0.0, 1.0);
1746 if (node.alpha - new_alpha).abs() > f32::EPSILON {
1747 node.alpha = new_alpha;
1748 }
1750 }
1751
1752 fn capabilities(&self) -> NodeCapabilities {
1753 NodeCapabilities::DRAW
1754 }
1755}
1756
1757#[derive(Debug)]
1763pub struct ClipToBoundsNode {
1764 state: NodeState,
1765}
1766
1767impl ClipToBoundsNode {
1768 pub fn new() -> Self {
1769 Self {
1770 state: NodeState::new(),
1771 }
1772 }
1773}
1774
1775impl DelegatableNode for ClipToBoundsNode {
1776 fn node_state(&self) -> &NodeState {
1777 &self.state
1778 }
1779}
1780
1781impl ModifierNode for ClipToBoundsNode {
1782 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1783 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1784 }
1785
1786 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1787 Some(self)
1788 }
1789
1790 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1791 Some(self)
1792 }
1793}
1794
1795impl DrawModifierNode for ClipToBoundsNode {
1796 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1797}
1798
1799#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1801pub struct ClipToBoundsElement;
1802
1803impl ClipToBoundsElement {
1804 pub fn new() -> Self {
1805 Self
1806 }
1807}
1808
1809impl ModifierNodeElement for ClipToBoundsElement {
1810 type Node = ClipToBoundsNode;
1811
1812 fn create(&self) -> Self::Node {
1813 ClipToBoundsNode::new()
1814 }
1815
1816 fn update(&self, _node: &mut Self::Node) {}
1817
1818 fn capabilities(&self) -> NodeCapabilities {
1819 NodeCapabilities::DRAW
1820 }
1821}
1822
1823pub struct DrawCommandNode {
1829 commands: Vec<DrawCommand>,
1830 state: NodeState,
1831}
1832
1833impl DrawCommandNode {
1834 pub fn new(commands: Vec<DrawCommand>) -> Self {
1835 Self {
1836 commands,
1837 state: NodeState::new(),
1838 }
1839 }
1840
1841 pub fn commands(&self) -> &[DrawCommand] {
1842 &self.commands
1843 }
1844}
1845
1846impl DelegatableNode for DrawCommandNode {
1847 fn node_state(&self) -> &NodeState {
1848 &self.state
1849 }
1850}
1851
1852impl ModifierNode for DrawCommandNode {
1853 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1854 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1855 }
1856
1857 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1858 Some(self)
1859 }
1860
1861 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1862 Some(self)
1863 }
1864}
1865
1866impl DrawModifierNode for DrawCommandNode {
1867 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1868}
1869
1870fn draw_command_tag(cmd: &DrawCommand) -> u8 {
1871 match cmd {
1872 DrawCommand::Behind(_) => 0,
1873 DrawCommand::WithContent(_) => 1,
1874 DrawCommand::Overlay(_) => 2,
1875 }
1876}
1877
1878fn draw_command_closure_identity(cmd: &DrawCommand) -> *const () {
1879 match cmd {
1880 DrawCommand::Behind(f) | DrawCommand::WithContent(f) | DrawCommand::Overlay(f) => {
1881 Rc::as_ptr(f) as *const ()
1882 }
1883 }
1884}
1885
1886#[derive(Clone)]
1888pub struct DrawCommandElement {
1889 commands: Vec<DrawCommand>,
1890}
1891
1892impl DrawCommandElement {
1893 pub fn new(command: DrawCommand) -> Self {
1894 Self {
1895 commands: vec![command],
1896 }
1897 }
1898
1899 pub fn from_commands(commands: Vec<DrawCommand>) -> Self {
1900 Self { commands }
1901 }
1902}
1903
1904impl std::fmt::Debug for DrawCommandElement {
1905 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1906 f.debug_struct("DrawCommandElement")
1907 .field("commands", &self.commands.len())
1908 .finish()
1909 }
1910}
1911
1912impl PartialEq for DrawCommandElement {
1913 fn eq(&self, other: &Self) -> bool {
1914 if self.commands.len() != other.commands.len() {
1915 return false;
1916 }
1917 self.commands
1918 .iter()
1919 .zip(other.commands.iter())
1920 .all(|(a, b)| {
1921 draw_command_tag(a) == draw_command_tag(b)
1922 && draw_command_closure_identity(a) == draw_command_closure_identity(b)
1923 })
1924 }
1925}
1926
1927impl Eq for DrawCommandElement {}
1928
1929impl std::hash::Hash for DrawCommandElement {
1930 fn hash<H: Hasher>(&self, state: &mut H) {
1931 "draw_commands".hash(state);
1932 self.commands.len().hash(state);
1933 for command in &self.commands {
1934 draw_command_tag(command).hash(state);
1935 (draw_command_closure_identity(command) as usize).hash(state);
1936 }
1937 }
1938}
1939
1940impl ModifierNodeElement for DrawCommandElement {
1941 type Node = DrawCommandNode;
1942
1943 fn create(&self) -> Self::Node {
1944 DrawCommandNode::new(self.commands.clone())
1945 }
1946
1947 fn update(&self, node: &mut Self::Node) {
1948 node.commands = self.commands.clone();
1949 }
1950
1951 fn capabilities(&self) -> NodeCapabilities {
1952 NodeCapabilities::DRAW
1953 }
1954}
1955
1956#[derive(Debug)]
1964pub struct OffsetNode {
1965 x: f32,
1966 y: f32,
1967 rtl_aware: bool,
1968 state: NodeState,
1969}
1970
1971impl OffsetNode {
1972 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
1973 Self {
1974 x,
1975 y,
1976 rtl_aware,
1977 state: NodeState::new(),
1978 }
1979 }
1980
1981 pub fn offset(&self) -> Point {
1982 Point {
1983 x: self.x,
1984 y: self.y,
1985 }
1986 }
1987
1988 pub fn rtl_aware(&self) -> bool {
1989 self.rtl_aware
1990 }
1991}
1992
1993impl DelegatableNode for OffsetNode {
1994 fn node_state(&self) -> &NodeState {
1995 &self.state
1996 }
1997}
1998
1999impl ModifierNode for OffsetNode {
2000 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2001 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2002 }
2003
2004 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
2005 Some(self)
2006 }
2007
2008 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
2009 Some(self)
2010 }
2011}
2012
2013impl LayoutModifierNode for OffsetNode {
2014 fn measure(
2015 &self,
2016 _context: &mut dyn ModifierNodeContext,
2017 measurable: &dyn Measurable,
2018 constraints: Constraints,
2019 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2020 let placeable = measurable.measure(constraints);
2022
2023 cranpose_ui_layout::LayoutModifierMeasureResult::new(
2025 Size {
2026 width: placeable.width(),
2027 height: placeable.height(),
2028 },
2029 self.x, self.y, )
2032 }
2033
2034 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2035 measurable.min_intrinsic_width(height)
2036 }
2037
2038 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2039 measurable.max_intrinsic_width(height)
2040 }
2041
2042 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2043 measurable.min_intrinsic_height(width)
2044 }
2045
2046 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2047 measurable.max_intrinsic_height(width)
2048 }
2049
2050 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
2051 Some(Box::new(OffsetMeasurementProxy {
2052 x: self.x,
2053 y: self.y,
2054 }))
2055 }
2056}
2057
2058struct OffsetMeasurementProxy {
2064 x: f32,
2065 y: f32,
2066}
2067
2068impl MeasurementProxy for OffsetMeasurementProxy {
2069 fn measure_proxy(
2070 &self,
2071 _context: &mut dyn ModifierNodeContext,
2072 wrapped: &dyn Measurable,
2073 constraints: Constraints,
2074 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2075 let placeable = wrapped.measure(constraints);
2077
2078 cranpose_ui_layout::LayoutModifierMeasureResult::new(
2080 Size {
2081 width: placeable.width(),
2082 height: placeable.height(),
2083 },
2084 self.x, self.y, )
2087 }
2088
2089 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2090 wrapped.min_intrinsic_width(height)
2091 }
2092
2093 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2094 wrapped.max_intrinsic_width(height)
2095 }
2096
2097 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2098 wrapped.min_intrinsic_height(width)
2099 }
2100
2101 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2102 wrapped.max_intrinsic_height(width)
2103 }
2104}
2105
2106#[derive(Debug, Clone, PartialEq)]
2110pub struct OffsetElement {
2111 x: f32,
2112 y: f32,
2113 rtl_aware: bool,
2114}
2115
2116impl OffsetElement {
2117 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
2118 Self { x, y, rtl_aware }
2119 }
2120}
2121
2122impl Hash for OffsetElement {
2123 fn hash<H: Hasher>(&self, state: &mut H) {
2124 hash_f32_value(state, self.x);
2125 hash_f32_value(state, self.y);
2126 self.rtl_aware.hash(state);
2127 }
2128}
2129
2130impl ModifierNodeElement for OffsetElement {
2131 type Node = OffsetNode;
2132
2133 fn create(&self) -> Self::Node {
2134 OffsetNode::new(self.x, self.y, self.rtl_aware)
2135 }
2136
2137 fn update(&self, node: &mut Self::Node) {
2138 if node.x != self.x || node.y != self.y || node.rtl_aware != self.rtl_aware {
2139 node.x = self.x;
2140 node.y = self.y;
2141 node.rtl_aware = self.rtl_aware;
2142 }
2143 }
2144
2145 fn capabilities(&self) -> NodeCapabilities {
2146 NodeCapabilities::LAYOUT
2147 }
2148}
2149
2150#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2156pub enum FillDirection {
2157 Horizontal,
2158 Vertical,
2159 Both,
2160}
2161
2162#[derive(Debug)]
2166pub struct FillNode {
2167 direction: FillDirection,
2168 fraction: f32,
2169 state: NodeState,
2170}
2171
2172impl FillNode {
2173 pub fn new(direction: FillDirection, fraction: f32) -> Self {
2174 Self {
2175 direction,
2176 fraction,
2177 state: NodeState::new(),
2178 }
2179 }
2180
2181 pub fn direction(&self) -> FillDirection {
2182 self.direction
2183 }
2184
2185 pub fn fraction(&self) -> f32 {
2186 self.fraction
2187 }
2188}
2189
2190impl DelegatableNode for FillNode {
2191 fn node_state(&self) -> &NodeState {
2192 &self.state
2193 }
2194}
2195
2196impl ModifierNode for FillNode {
2197 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2198 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2199 }
2200
2201 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
2202 Some(self)
2203 }
2204
2205 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
2206 Some(self)
2207 }
2208}
2209
2210impl LayoutModifierNode for FillNode {
2211 fn measure(
2212 &self,
2213 _context: &mut dyn ModifierNodeContext,
2214 measurable: &dyn Measurable,
2215 constraints: Constraints,
2216 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2217 let (fill_width, child_min_width, child_max_width) = if self.direction
2219 != FillDirection::Vertical
2220 && constraints.max_width != f32::INFINITY
2221 {
2222 let width = (constraints.max_width * self.fraction)
2223 .round()
2224 .clamp(constraints.min_width, constraints.max_width);
2225 (width, width, width)
2227 } else {
2228 (
2229 constraints.max_width,
2230 constraints.min_width,
2231 constraints.max_width,
2232 )
2233 };
2234
2235 let (fill_height, child_min_height, child_max_height) = if self.direction
2236 != FillDirection::Horizontal
2237 && constraints.max_height != f32::INFINITY
2238 {
2239 let height = (constraints.max_height * self.fraction)
2240 .round()
2241 .clamp(constraints.min_height, constraints.max_height);
2242 (height, height, height)
2244 } else {
2245 (
2246 constraints.max_height,
2247 constraints.min_height,
2248 constraints.max_height,
2249 )
2250 };
2251
2252 let fill_constraints = Constraints {
2253 min_width: child_min_width,
2254 max_width: child_max_width,
2255 min_height: child_min_height,
2256 max_height: child_max_height,
2257 };
2258
2259 let placeable = measurable.measure(fill_constraints);
2260
2261 let result_width = if self.direction != FillDirection::Vertical
2265 && constraints.max_width != f32::INFINITY
2266 {
2267 fill_width
2268 } else {
2269 placeable.width()
2270 };
2271
2272 let result_height = if self.direction != FillDirection::Horizontal
2273 && constraints.max_height != f32::INFINITY
2274 {
2275 fill_height
2276 } else {
2277 placeable.height()
2278 };
2279
2280 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2281 width: result_width,
2282 height: result_height,
2283 })
2284 }
2285
2286 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2287 measurable.min_intrinsic_width(height)
2288 }
2289
2290 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2291 measurable.max_intrinsic_width(height)
2292 }
2293
2294 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2295 measurable.min_intrinsic_height(width)
2296 }
2297
2298 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2299 measurable.max_intrinsic_height(width)
2300 }
2301
2302 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
2303 Some(Box::new(FillMeasurementProxy {
2304 direction: self.direction,
2305 fraction: self.fraction,
2306 }))
2307 }
2308}
2309
2310struct FillMeasurementProxy {
2315 direction: FillDirection,
2316 fraction: f32,
2317}
2318
2319impl MeasurementProxy for FillMeasurementProxy {
2320 fn measure_proxy(
2321 &self,
2322 _context: &mut dyn ModifierNodeContext,
2323 wrapped: &dyn Measurable,
2324 constraints: Constraints,
2325 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2326 let (fill_width, child_min_width, child_max_width) = if self.direction
2328 != FillDirection::Vertical
2329 && constraints.max_width != f32::INFINITY
2330 {
2331 let width = (constraints.max_width * self.fraction)
2332 .round()
2333 .clamp(constraints.min_width, constraints.max_width);
2334 (width, width, width)
2335 } else {
2336 (
2337 constraints.max_width,
2338 constraints.min_width,
2339 constraints.max_width,
2340 )
2341 };
2342
2343 let (fill_height, child_min_height, child_max_height) = if self.direction
2344 != FillDirection::Horizontal
2345 && constraints.max_height != f32::INFINITY
2346 {
2347 let height = (constraints.max_height * self.fraction)
2348 .round()
2349 .clamp(constraints.min_height, constraints.max_height);
2350 (height, height, height)
2351 } else {
2352 (
2353 constraints.max_height,
2354 constraints.min_height,
2355 constraints.max_height,
2356 )
2357 };
2358
2359 let fill_constraints = Constraints {
2360 min_width: child_min_width,
2361 max_width: child_max_width,
2362 min_height: child_min_height,
2363 max_height: child_max_height,
2364 };
2365
2366 let placeable = wrapped.measure(fill_constraints);
2367
2368 let result_width = if self.direction != FillDirection::Vertical
2370 && constraints.max_width != f32::INFINITY
2371 {
2372 fill_width
2373 } else {
2374 placeable.width()
2375 };
2376
2377 let result_height = if self.direction != FillDirection::Horizontal
2378 && constraints.max_height != f32::INFINITY
2379 {
2380 fill_height
2381 } else {
2382 placeable.height()
2383 };
2384
2385 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2386 width: result_width,
2387 height: result_height,
2388 })
2389 }
2390
2391 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2392 wrapped.min_intrinsic_width(height)
2393 }
2394
2395 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2396 wrapped.max_intrinsic_width(height)
2397 }
2398
2399 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2400 wrapped.min_intrinsic_height(width)
2401 }
2402
2403 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2404 wrapped.max_intrinsic_height(width)
2405 }
2406}
2407
2408#[derive(Debug, Clone, PartialEq)]
2412pub struct FillElement {
2413 direction: FillDirection,
2414 fraction: f32,
2415}
2416
2417impl FillElement {
2418 pub fn width(fraction: f32) -> Self {
2419 Self {
2420 direction: FillDirection::Horizontal,
2421 fraction,
2422 }
2423 }
2424
2425 pub fn height(fraction: f32) -> Self {
2426 Self {
2427 direction: FillDirection::Vertical,
2428 fraction,
2429 }
2430 }
2431
2432 pub fn size(fraction: f32) -> Self {
2433 Self {
2434 direction: FillDirection::Both,
2435 fraction,
2436 }
2437 }
2438}
2439
2440impl Hash for FillElement {
2441 fn hash<H: Hasher>(&self, state: &mut H) {
2442 self.direction.hash(state);
2443 hash_f32_value(state, self.fraction);
2444 }
2445}
2446
2447impl ModifierNodeElement for FillElement {
2448 type Node = FillNode;
2449
2450 fn create(&self) -> Self::Node {
2451 FillNode::new(self.direction, self.fraction)
2452 }
2453
2454 fn update(&self, node: &mut Self::Node) {
2455 if node.direction != self.direction || node.fraction != self.fraction {
2456 node.direction = self.direction;
2457 node.fraction = self.fraction;
2458 }
2459 }
2460
2461 fn capabilities(&self) -> NodeCapabilities {
2462 NodeCapabilities::LAYOUT
2463 }
2464}
2465
2466#[derive(Debug)]
2472pub struct WeightNode {
2473 weight: f32,
2474 fill: bool,
2475 state: NodeState,
2476}
2477
2478impl WeightNode {
2479 pub fn new(weight: f32, fill: bool) -> Self {
2480 Self {
2481 weight,
2482 fill,
2483 state: NodeState::new(),
2484 }
2485 }
2486
2487 pub fn layout_weight(&self) -> LayoutWeight {
2488 LayoutWeight {
2489 weight: self.weight,
2490 fill: self.fill,
2491 }
2492 }
2493}
2494
2495impl DelegatableNode for WeightNode {
2496 fn node_state(&self) -> &NodeState {
2497 &self.state
2498 }
2499}
2500
2501impl ModifierNode for WeightNode {
2502 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2503 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2504 }
2505}
2506
2507#[derive(Debug, Clone, PartialEq)]
2509pub struct WeightElement {
2510 weight: f32,
2511 fill: bool,
2512}
2513
2514impl WeightElement {
2515 pub fn new(weight: f32, fill: bool) -> Self {
2516 Self { weight, fill }
2517 }
2518}
2519
2520impl Hash for WeightElement {
2521 fn hash<H: Hasher>(&self, state: &mut H) {
2522 hash_f32_value(state, self.weight);
2523 self.fill.hash(state);
2524 }
2525}
2526
2527impl ModifierNodeElement for WeightElement {
2528 type Node = WeightNode;
2529
2530 fn create(&self) -> Self::Node {
2531 WeightNode::new(self.weight, self.fill)
2532 }
2533
2534 fn update(&self, node: &mut Self::Node) {
2535 if node.weight != self.weight || node.fill != self.fill {
2536 node.weight = self.weight;
2537 node.fill = self.fill;
2538 }
2539 }
2540
2541 fn capabilities(&self) -> NodeCapabilities {
2542 NodeCapabilities::LAYOUT
2543 }
2544}
2545
2546#[derive(Debug)]
2552pub struct AlignmentNode {
2553 box_alignment: Option<Alignment>,
2554 column_alignment: Option<HorizontalAlignment>,
2555 row_alignment: Option<VerticalAlignment>,
2556 state: NodeState,
2557}
2558
2559impl AlignmentNode {
2560 pub fn new(
2561 box_alignment: Option<Alignment>,
2562 column_alignment: Option<HorizontalAlignment>,
2563 row_alignment: Option<VerticalAlignment>,
2564 ) -> Self {
2565 Self {
2566 box_alignment,
2567 column_alignment,
2568 row_alignment,
2569 state: NodeState::new(),
2570 }
2571 }
2572
2573 pub fn box_alignment(&self) -> Option<Alignment> {
2574 self.box_alignment
2575 }
2576
2577 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
2578 self.column_alignment
2579 }
2580
2581 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
2582 self.row_alignment
2583 }
2584}
2585
2586impl DelegatableNode for AlignmentNode {
2587 fn node_state(&self) -> &NodeState {
2588 &self.state
2589 }
2590}
2591
2592impl ModifierNode for AlignmentNode {
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 AlignmentElement {
2601 box_alignment: Option<Alignment>,
2602 column_alignment: Option<HorizontalAlignment>,
2603 row_alignment: Option<VerticalAlignment>,
2604}
2605
2606impl AlignmentElement {
2607 pub fn box_alignment(alignment: Alignment) -> Self {
2608 Self {
2609 box_alignment: Some(alignment),
2610 column_alignment: None,
2611 row_alignment: None,
2612 }
2613 }
2614
2615 pub fn column_alignment(alignment: HorizontalAlignment) -> Self {
2616 Self {
2617 box_alignment: None,
2618 column_alignment: Some(alignment),
2619 row_alignment: None,
2620 }
2621 }
2622
2623 pub fn row_alignment(alignment: VerticalAlignment) -> Self {
2624 Self {
2625 box_alignment: None,
2626 column_alignment: None,
2627 row_alignment: Some(alignment),
2628 }
2629 }
2630}
2631
2632impl Hash for AlignmentElement {
2633 fn hash<H: Hasher>(&self, state: &mut H) {
2634 if let Some(alignment) = self.box_alignment {
2635 state.write_u8(1);
2636 hash_alignment(state, alignment);
2637 } else {
2638 state.write_u8(0);
2639 }
2640 if let Some(alignment) = self.column_alignment {
2641 state.write_u8(1);
2642 hash_horizontal_alignment(state, alignment);
2643 } else {
2644 state.write_u8(0);
2645 }
2646 if let Some(alignment) = self.row_alignment {
2647 state.write_u8(1);
2648 hash_vertical_alignment(state, alignment);
2649 } else {
2650 state.write_u8(0);
2651 }
2652 }
2653}
2654
2655impl ModifierNodeElement for AlignmentElement {
2656 type Node = AlignmentNode;
2657
2658 fn create(&self) -> Self::Node {
2659 AlignmentNode::new(
2660 self.box_alignment,
2661 self.column_alignment,
2662 self.row_alignment,
2663 )
2664 }
2665
2666 fn update(&self, node: &mut Self::Node) {
2667 if node.box_alignment != self.box_alignment {
2668 node.box_alignment = self.box_alignment;
2669 }
2670 if node.column_alignment != self.column_alignment {
2671 node.column_alignment = self.column_alignment;
2672 }
2673 if node.row_alignment != self.row_alignment {
2674 node.row_alignment = self.row_alignment;
2675 }
2676 }
2677
2678 fn capabilities(&self) -> NodeCapabilities {
2679 NodeCapabilities::LAYOUT
2680 }
2681}
2682
2683#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2688pub enum IntrinsicAxis {
2689 Width,
2690 Height,
2691}
2692
2693#[derive(Debug)]
2695pub struct IntrinsicSizeNode {
2696 axis: IntrinsicAxis,
2697 size: IntrinsicSize,
2698 state: NodeState,
2699}
2700
2701impl IntrinsicSizeNode {
2702 pub fn new(axis: IntrinsicAxis, size: IntrinsicSize) -> Self {
2703 Self {
2704 axis,
2705 size,
2706 state: NodeState::new(),
2707 }
2708 }
2709
2710 pub fn axis(&self) -> IntrinsicAxis {
2711 self.axis
2712 }
2713
2714 pub fn intrinsic_size(&self) -> IntrinsicSize {
2715 self.size
2716 }
2717}
2718
2719impl DelegatableNode for IntrinsicSizeNode {
2720 fn node_state(&self) -> &NodeState {
2721 &self.state
2722 }
2723}
2724
2725impl ModifierNode for IntrinsicSizeNode {
2726 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2727 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2728 }
2729}
2730
2731#[derive(Debug, Clone, PartialEq)]
2733pub struct IntrinsicSizeElement {
2734 axis: IntrinsicAxis,
2735 size: IntrinsicSize,
2736}
2737
2738impl IntrinsicSizeElement {
2739 pub fn width(size: IntrinsicSize) -> Self {
2740 Self {
2741 axis: IntrinsicAxis::Width,
2742 size,
2743 }
2744 }
2745
2746 pub fn height(size: IntrinsicSize) -> Self {
2747 Self {
2748 axis: IntrinsicAxis::Height,
2749 size,
2750 }
2751 }
2752}
2753
2754impl Hash for IntrinsicSizeElement {
2755 fn hash<H: Hasher>(&self, state: &mut H) {
2756 state.write_u8(match self.axis {
2757 IntrinsicAxis::Width => 0,
2758 IntrinsicAxis::Height => 1,
2759 });
2760 state.write_u8(match self.size {
2761 IntrinsicSize::Min => 0,
2762 IntrinsicSize::Max => 1,
2763 });
2764 }
2765}
2766
2767impl ModifierNodeElement for IntrinsicSizeElement {
2768 type Node = IntrinsicSizeNode;
2769
2770 fn create(&self) -> Self::Node {
2771 IntrinsicSizeNode::new(self.axis, self.size)
2772 }
2773
2774 fn update(&self, node: &mut Self::Node) {
2775 if node.axis != self.axis {
2776 node.axis = self.axis;
2777 }
2778 if node.size != self.size {
2779 node.size = self.size;
2780 }
2781 }
2782
2783 fn capabilities(&self) -> NodeCapabilities {
2784 NodeCapabilities::LAYOUT
2785 }
2786}
2787
2788#[cfg(test)]
2789#[path = "tests/modifier_nodes_tests.rs"]
2790mod tests;