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 if let Some(resolve) = node.layer_resolver() {
675 node.layer = resolve();
676 }
677 node
678 }
679
680 pub fn layer(&self) -> GraphicsLayer {
681 if let Some(resolve) = self.layer_resolver() {
682 resolve()
683 } else {
684 self.layer.clone()
685 }
686 }
687
688 pub fn layer_resolver(&self) -> Option<Rc<dyn Fn() -> GraphicsLayer>> {
689 self.layer_resolver.as_ref().map(|resolve| {
690 let resolve = resolve.clone();
691 match (&self.lazy_observer, self.lazy_scope_id) {
692 (Some(observer), Some(scope_id)) => {
693 let observer = observer.clone();
694 Rc::new(move || {
695 observer.observe_reads(
696 scope_id,
697 |_| crate::request_render_invalidation(),
698 || resolve(),
699 )
700 }) as Rc<dyn Fn() -> GraphicsLayer>
701 }
702 _ => resolve,
703 }
704 })
705 }
706
707 fn set_static(&mut self, layer: GraphicsLayer) {
708 self.layer = layer;
709 self.layer_resolver = None;
710 self.clear_lazy_observation();
711 }
712
713 fn set_lazy(&mut self, layer_resolver: Rc<dyn Fn() -> GraphicsLayer>) {
714 self.layer_resolver = Some(layer_resolver);
715 self.ensure_lazy_observation();
716 if let Some(resolve) = self.layer_resolver() {
717 self.layer = resolve();
718 }
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 }
1537 })
1538 }
1539
1540 pub fn handler(&self) -> Rc<dyn Fn(Point)> {
1541 self.on_click.clone()
1542 }
1543}
1544
1545impl DelegatableNode for ClickableNode {
1546 fn node_state(&self) -> &NodeState {
1547 &self.state
1548 }
1549}
1550
1551impl ModifierNode for ClickableNode {
1552 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1553 context.invalidate(cranpose_foundation::InvalidationKind::PointerInput);
1554 }
1555
1556 fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
1557 Some(self)
1558 }
1559
1560 fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
1561 Some(self)
1562 }
1563}
1564
1565impl PointerInputNode for ClickableNode {
1566 fn on_pointer_event(
1567 &mut self,
1568 _context: &mut dyn ModifierNodeContext,
1569 event: &PointerEvent,
1570 ) -> bool {
1571 (self.cached_handler)(event.clone());
1574 event.is_consumed()
1575 }
1576
1577 fn hit_test(&self, _x: f32, _y: f32) -> bool {
1578 true
1580 }
1581
1582 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
1583 Some(self.cached_handler.clone())
1586 }
1587}
1588
1589#[derive(Clone)]
1591pub struct ClickableElement {
1592 on_click: Rc<dyn Fn(Point)>,
1593}
1594
1595impl ClickableElement {
1596 pub fn new(on_click: impl Fn(Point) + 'static) -> Self {
1597 Self {
1598 on_click: Rc::new(on_click),
1599 }
1600 }
1601
1602 pub fn with_handler(on_click: Rc<dyn Fn(Point)>) -> Self {
1603 Self { on_click }
1604 }
1605}
1606
1607impl std::fmt::Debug for ClickableElement {
1608 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1609 f.debug_struct("ClickableElement").finish()
1610 }
1611}
1612
1613impl PartialEq for ClickableElement {
1614 fn eq(&self, _other: &Self) -> bool {
1615 true
1619 }
1620}
1621
1622impl Eq for ClickableElement {}
1623
1624impl Hash for ClickableElement {
1625 fn hash<H: Hasher>(&self, state: &mut H) {
1626 "clickable".hash(state);
1628 }
1629}
1630
1631impl ModifierNodeElement for ClickableElement {
1632 type Node = ClickableNode;
1633
1634 fn create(&self) -> Self::Node {
1635 ClickableNode::with_handler(self.on_click.clone())
1636 }
1637
1638 fn update(&self, node: &mut Self::Node) {
1644 node.on_click = self.on_click.clone();
1647 node.cached_handler =
1649 ClickableNode::create_handler(node.on_click.clone(), node.press_position.clone());
1650 }
1651
1652 fn capabilities(&self) -> NodeCapabilities {
1653 NodeCapabilities::POINTER_INPUT
1654 }
1655
1656 fn always_update(&self) -> bool {
1657 true
1659 }
1660}
1661
1662pub struct PointerEventHandlerNode {
1668 handler: Rc<dyn Fn(PointerEvent)>,
1669 state: NodeState,
1670}
1671
1672impl std::fmt::Debug for PointerEventHandlerNode {
1673 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1674 f.debug_struct("PointerEventHandlerNode").finish()
1675 }
1676}
1677
1678impl PointerEventHandlerNode {
1679 pub fn new(handler: Rc<dyn Fn(PointerEvent)>) -> Self {
1680 Self {
1681 handler,
1682 state: NodeState::new(),
1683 }
1684 }
1685
1686 #[allow(dead_code)] pub fn handler(&self) -> Rc<dyn Fn(PointerEvent)> {
1688 self.handler.clone()
1689 }
1690}
1691
1692impl DelegatableNode for PointerEventHandlerNode {
1693 fn node_state(&self) -> &NodeState {
1694 &self.state
1695 }
1696}
1697
1698impl ModifierNode for PointerEventHandlerNode {
1699 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1700 context.invalidate(cranpose_foundation::InvalidationKind::PointerInput);
1701 }
1702
1703 fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
1704 Some(self)
1705 }
1706
1707 fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
1708 Some(self)
1709 }
1710}
1711
1712impl PointerInputNode for PointerEventHandlerNode {
1713 fn on_pointer_event(
1714 &mut self,
1715 _context: &mut dyn ModifierNodeContext,
1716 event: &PointerEvent,
1717 ) -> bool {
1718 (self.handler)(event.clone());
1719 false
1720 }
1721
1722 fn hit_test(&self, _x: f32, _y: f32) -> bool {
1723 true
1724 }
1725
1726 fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
1727 Some(self.handler.clone())
1728 }
1729}
1730
1731#[derive(Clone)]
1733pub struct PointerEventHandlerElement {
1734 handler: Rc<dyn Fn(PointerEvent)>,
1735}
1736
1737impl PointerEventHandlerElement {
1738 #[allow(dead_code)] pub fn new(handler: Rc<dyn Fn(PointerEvent)>) -> Self {
1740 Self { handler }
1741 }
1742}
1743
1744impl std::fmt::Debug for PointerEventHandlerElement {
1745 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1746 f.debug_struct("PointerEventHandlerElement").finish()
1747 }
1748}
1749
1750impl PartialEq for PointerEventHandlerElement {
1751 fn eq(&self, other: &Self) -> bool {
1752 Rc::ptr_eq(&self.handler, &other.handler)
1753 }
1754}
1755
1756impl Eq for PointerEventHandlerElement {}
1757
1758impl Hash for PointerEventHandlerElement {
1759 fn hash<H: Hasher>(&self, state: &mut H) {
1760 let ptr = Rc::as_ptr(&self.handler) as *const ();
1761 (ptr as usize).hash(state);
1762 }
1763}
1764
1765impl ModifierNodeElement for PointerEventHandlerElement {
1766 type Node = PointerEventHandlerNode;
1767
1768 fn create(&self) -> Self::Node {
1769 PointerEventHandlerNode::new(self.handler.clone())
1770 }
1771
1772 fn update(&self, node: &mut Self::Node) {
1773 node.handler = self.handler.clone();
1774 }
1775
1776 fn capabilities(&self) -> NodeCapabilities {
1777 NodeCapabilities::POINTER_INPUT
1778 }
1779}
1780
1781#[derive(Debug)]
1787pub struct AlphaNode {
1788 alpha: f32,
1789 state: NodeState,
1790}
1791
1792impl AlphaNode {
1793 pub fn new(alpha: f32) -> Self {
1794 Self {
1795 alpha: alpha.clamp(0.0, 1.0),
1796 state: NodeState::new(),
1797 }
1798 }
1799}
1800
1801impl DelegatableNode for AlphaNode {
1802 fn node_state(&self) -> &NodeState {
1803 &self.state
1804 }
1805}
1806
1807impl ModifierNode for AlphaNode {
1808 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1809 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1810 }
1811
1812 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1813 Some(self)
1814 }
1815
1816 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1817 Some(self)
1818 }
1819}
1820
1821impl DrawModifierNode for AlphaNode {
1822 fn draw(&self, _draw_scope: &mut dyn DrawScope) {
1823 }
1831}
1832
1833#[derive(Debug, Clone, PartialEq)]
1835pub struct AlphaElement {
1836 alpha: f32,
1837}
1838
1839impl AlphaElement {
1840 pub fn new(alpha: f32) -> Self {
1841 Self {
1842 alpha: alpha.clamp(0.0, 1.0),
1843 }
1844 }
1845}
1846
1847impl Hash for AlphaElement {
1848 fn hash<H: Hasher>(&self, state: &mut H) {
1849 hash_f32_value(state, self.alpha);
1850 }
1851}
1852
1853impl ModifierNodeElement for AlphaElement {
1854 type Node = AlphaNode;
1855
1856 fn create(&self) -> Self::Node {
1857 AlphaNode::new(self.alpha)
1858 }
1859
1860 fn update(&self, node: &mut Self::Node) {
1861 let new_alpha = self.alpha.clamp(0.0, 1.0);
1862 if (node.alpha - new_alpha).abs() > f32::EPSILON {
1863 node.alpha = new_alpha;
1864 }
1866 }
1867
1868 fn capabilities(&self) -> NodeCapabilities {
1869 NodeCapabilities::DRAW
1870 }
1871}
1872
1873#[derive(Debug)]
1879pub struct ClipToBoundsNode {
1880 state: NodeState,
1881}
1882
1883impl ClipToBoundsNode {
1884 pub fn new() -> Self {
1885 Self {
1886 state: NodeState::new(),
1887 }
1888 }
1889}
1890
1891impl DelegatableNode for ClipToBoundsNode {
1892 fn node_state(&self) -> &NodeState {
1893 &self.state
1894 }
1895}
1896
1897impl ModifierNode for ClipToBoundsNode {
1898 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1899 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1900 }
1901
1902 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1903 Some(self)
1904 }
1905
1906 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1907 Some(self)
1908 }
1909}
1910
1911impl DrawModifierNode for ClipToBoundsNode {
1912 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1913}
1914
1915#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1917pub struct ClipToBoundsElement;
1918
1919impl ClipToBoundsElement {
1920 pub fn new() -> Self {
1921 Self
1922 }
1923}
1924
1925impl ModifierNodeElement for ClipToBoundsElement {
1926 type Node = ClipToBoundsNode;
1927
1928 fn create(&self) -> Self::Node {
1929 ClipToBoundsNode::new()
1930 }
1931
1932 fn update(&self, _node: &mut Self::Node) {}
1933
1934 fn capabilities(&self) -> NodeCapabilities {
1935 NodeCapabilities::DRAW
1936 }
1937}
1938
1939pub struct DrawCommandNode {
1945 commands: Vec<DrawCommand>,
1946 state: NodeState,
1947}
1948
1949impl DrawCommandNode {
1950 pub fn new(commands: Vec<DrawCommand>) -> Self {
1951 Self {
1952 commands,
1953 state: NodeState::new(),
1954 }
1955 }
1956
1957 pub fn commands(&self) -> &[DrawCommand] {
1958 &self.commands
1959 }
1960}
1961
1962impl DelegatableNode for DrawCommandNode {
1963 fn node_state(&self) -> &NodeState {
1964 &self.state
1965 }
1966}
1967
1968impl ModifierNode for DrawCommandNode {
1969 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
1970 context.invalidate(cranpose_foundation::InvalidationKind::Draw);
1971 }
1972
1973 fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
1974 Some(self)
1975 }
1976
1977 fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
1978 Some(self)
1979 }
1980}
1981
1982impl DrawModifierNode for DrawCommandNode {
1983 fn draw(&self, _draw_scope: &mut dyn DrawScope) {}
1984}
1985
1986fn draw_command_tag(cmd: &DrawCommand) -> u8 {
1987 match cmd {
1988 DrawCommand::Behind(_) => 0,
1989 DrawCommand::WithContent(_) => 1,
1990 DrawCommand::Overlay(_) => 2,
1991 }
1992}
1993
1994fn draw_command_closure_identity(cmd: &DrawCommand) -> *const () {
1995 match cmd {
1996 DrawCommand::Behind(f) | DrawCommand::WithContent(f) | DrawCommand::Overlay(f) => {
1997 Rc::as_ptr(f) as *const ()
1998 }
1999 }
2000}
2001
2002#[derive(Clone)]
2004pub struct DrawCommandElement {
2005 commands: Vec<DrawCommand>,
2006}
2007
2008impl DrawCommandElement {
2009 pub fn new(command: DrawCommand) -> Self {
2010 Self {
2011 commands: vec![command],
2012 }
2013 }
2014
2015 pub fn from_commands(commands: Vec<DrawCommand>) -> Self {
2016 Self { commands }
2017 }
2018}
2019
2020impl std::fmt::Debug for DrawCommandElement {
2021 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2022 f.debug_struct("DrawCommandElement")
2023 .field("commands", &self.commands.len())
2024 .finish()
2025 }
2026}
2027
2028impl PartialEq for DrawCommandElement {
2029 fn eq(&self, other: &Self) -> bool {
2030 if self.commands.len() != other.commands.len() {
2031 return false;
2032 }
2033 self.commands
2034 .iter()
2035 .zip(other.commands.iter())
2036 .all(|(a, b)| {
2037 draw_command_tag(a) == draw_command_tag(b)
2038 && draw_command_closure_identity(a) == draw_command_closure_identity(b)
2039 })
2040 }
2041}
2042
2043impl Eq for DrawCommandElement {}
2044
2045impl std::hash::Hash for DrawCommandElement {
2046 fn hash<H: Hasher>(&self, state: &mut H) {
2047 "draw_commands".hash(state);
2048 self.commands.len().hash(state);
2049 for command in &self.commands {
2050 draw_command_tag(command).hash(state);
2051 (draw_command_closure_identity(command) as usize).hash(state);
2052 }
2053 }
2054}
2055
2056impl ModifierNodeElement for DrawCommandElement {
2057 type Node = DrawCommandNode;
2058
2059 fn create(&self) -> Self::Node {
2060 DrawCommandNode::new(self.commands.clone())
2061 }
2062
2063 fn update(&self, node: &mut Self::Node) {
2064 node.commands = self.commands.clone();
2065 }
2066
2067 fn capabilities(&self) -> NodeCapabilities {
2068 NodeCapabilities::DRAW
2069 }
2070}
2071
2072#[derive(Debug)]
2080pub struct OffsetNode {
2081 x: f32,
2082 y: f32,
2083 rtl_aware: bool,
2084 state: NodeState,
2085}
2086
2087impl OffsetNode {
2088 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
2089 Self {
2090 x,
2091 y,
2092 rtl_aware,
2093 state: NodeState::new(),
2094 }
2095 }
2096
2097 pub fn offset(&self) -> Point {
2098 Point {
2099 x: self.x,
2100 y: self.y,
2101 }
2102 }
2103
2104 pub fn rtl_aware(&self) -> bool {
2105 self.rtl_aware
2106 }
2107}
2108
2109impl DelegatableNode for OffsetNode {
2110 fn node_state(&self) -> &NodeState {
2111 &self.state
2112 }
2113}
2114
2115impl ModifierNode for OffsetNode {
2116 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2117 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2118 }
2119
2120 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
2121 Some(self)
2122 }
2123
2124 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
2125 Some(self)
2126 }
2127}
2128
2129impl LayoutModifierNode for OffsetNode {
2130 fn measure(
2131 &self,
2132 _context: &mut dyn ModifierNodeContext,
2133 measurable: &dyn Measurable,
2134 constraints: Constraints,
2135 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2136 let placeable = measurable.measure(constraints);
2138
2139 cranpose_ui_layout::LayoutModifierMeasureResult::new(
2141 Size {
2142 width: placeable.width(),
2143 height: placeable.height(),
2144 },
2145 self.x, self.y, )
2148 }
2149
2150 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2151 measurable.min_intrinsic_width(height)
2152 }
2153
2154 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2155 measurable.max_intrinsic_width(height)
2156 }
2157
2158 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2159 measurable.min_intrinsic_height(width)
2160 }
2161
2162 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2163 measurable.max_intrinsic_height(width)
2164 }
2165
2166 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
2167 Some(Box::new(OffsetMeasurementProxy {
2168 x: self.x,
2169 y: self.y,
2170 rtl_aware: self.rtl_aware,
2171 }))
2172 }
2173}
2174
2175struct OffsetMeasurementProxy {
2181 x: f32,
2182 y: f32,
2183 #[allow(dead_code)]
2184 rtl_aware: bool,
2185}
2186
2187impl MeasurementProxy for OffsetMeasurementProxy {
2188 fn measure_proxy(
2189 &self,
2190 _context: &mut dyn ModifierNodeContext,
2191 wrapped: &dyn Measurable,
2192 constraints: Constraints,
2193 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2194 let placeable = wrapped.measure(constraints);
2196
2197 cranpose_ui_layout::LayoutModifierMeasureResult::new(
2199 Size {
2200 width: placeable.width(),
2201 height: placeable.height(),
2202 },
2203 self.x, self.y, )
2206 }
2207
2208 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2209 wrapped.min_intrinsic_width(height)
2210 }
2211
2212 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2213 wrapped.max_intrinsic_width(height)
2214 }
2215
2216 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2217 wrapped.min_intrinsic_height(width)
2218 }
2219
2220 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2221 wrapped.max_intrinsic_height(width)
2222 }
2223}
2224
2225#[derive(Debug, Clone, PartialEq)]
2229pub struct OffsetElement {
2230 x: f32,
2231 y: f32,
2232 rtl_aware: bool,
2233}
2234
2235impl OffsetElement {
2236 pub fn new(x: f32, y: f32, rtl_aware: bool) -> Self {
2237 Self { x, y, rtl_aware }
2238 }
2239}
2240
2241impl Hash for OffsetElement {
2242 fn hash<H: Hasher>(&self, state: &mut H) {
2243 hash_f32_value(state, self.x);
2244 hash_f32_value(state, self.y);
2245 self.rtl_aware.hash(state);
2246 }
2247}
2248
2249impl ModifierNodeElement for OffsetElement {
2250 type Node = OffsetNode;
2251
2252 fn create(&self) -> Self::Node {
2253 OffsetNode::new(self.x, self.y, self.rtl_aware)
2254 }
2255
2256 fn update(&self, node: &mut Self::Node) {
2257 if node.x != self.x || node.y != self.y || node.rtl_aware != self.rtl_aware {
2258 node.x = self.x;
2259 node.y = self.y;
2260 node.rtl_aware = self.rtl_aware;
2261 }
2262 }
2263
2264 fn capabilities(&self) -> NodeCapabilities {
2265 NodeCapabilities::LAYOUT
2266 }
2267}
2268
2269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2275pub enum FillDirection {
2276 Horizontal,
2277 Vertical,
2278 Both,
2279}
2280
2281#[derive(Debug)]
2285pub struct FillNode {
2286 direction: FillDirection,
2287 fraction: f32,
2288 state: NodeState,
2289}
2290
2291impl FillNode {
2292 pub fn new(direction: FillDirection, fraction: f32) -> Self {
2293 Self {
2294 direction,
2295 fraction,
2296 state: NodeState::new(),
2297 }
2298 }
2299
2300 pub fn direction(&self) -> FillDirection {
2301 self.direction
2302 }
2303
2304 pub fn fraction(&self) -> f32 {
2305 self.fraction
2306 }
2307}
2308
2309impl DelegatableNode for FillNode {
2310 fn node_state(&self) -> &NodeState {
2311 &self.state
2312 }
2313}
2314
2315impl ModifierNode for FillNode {
2316 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2317 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2318 }
2319
2320 fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
2321 Some(self)
2322 }
2323
2324 fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
2325 Some(self)
2326 }
2327}
2328
2329impl LayoutModifierNode for FillNode {
2330 fn measure(
2331 &self,
2332 _context: &mut dyn ModifierNodeContext,
2333 measurable: &dyn Measurable,
2334 constraints: Constraints,
2335 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2336 let (fill_width, child_min_width, child_max_width) = if self.direction
2338 != FillDirection::Vertical
2339 && constraints.max_width != f32::INFINITY
2340 {
2341 let width = (constraints.max_width * self.fraction)
2342 .round()
2343 .clamp(constraints.min_width, constraints.max_width);
2344 (width, width, width)
2346 } else {
2347 (
2348 constraints.max_width,
2349 constraints.min_width,
2350 constraints.max_width,
2351 )
2352 };
2353
2354 let (fill_height, child_min_height, child_max_height) = if self.direction
2355 != FillDirection::Horizontal
2356 && constraints.max_height != f32::INFINITY
2357 {
2358 let height = (constraints.max_height * self.fraction)
2359 .round()
2360 .clamp(constraints.min_height, constraints.max_height);
2361 (height, height, height)
2363 } else {
2364 (
2365 constraints.max_height,
2366 constraints.min_height,
2367 constraints.max_height,
2368 )
2369 };
2370
2371 let fill_constraints = Constraints {
2372 min_width: child_min_width,
2373 max_width: child_max_width,
2374 min_height: child_min_height,
2375 max_height: child_max_height,
2376 };
2377
2378 let placeable = measurable.measure(fill_constraints);
2379
2380 let result_width = if self.direction != FillDirection::Vertical
2384 && constraints.max_width != f32::INFINITY
2385 {
2386 fill_width
2387 } else {
2388 placeable.width()
2389 };
2390
2391 let result_height = if self.direction != FillDirection::Horizontal
2392 && constraints.max_height != f32::INFINITY
2393 {
2394 fill_height
2395 } else {
2396 placeable.height()
2397 };
2398
2399 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2400 width: result_width,
2401 height: result_height,
2402 })
2403 }
2404
2405 fn min_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2406 measurable.min_intrinsic_width(height)
2407 }
2408
2409 fn max_intrinsic_width(&self, measurable: &dyn Measurable, height: f32) -> f32 {
2410 measurable.max_intrinsic_width(height)
2411 }
2412
2413 fn min_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2414 measurable.min_intrinsic_height(width)
2415 }
2416
2417 fn max_intrinsic_height(&self, measurable: &dyn Measurable, width: f32) -> f32 {
2418 measurable.max_intrinsic_height(width)
2419 }
2420
2421 fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
2422 Some(Box::new(FillMeasurementProxy {
2423 direction: self.direction,
2424 fraction: self.fraction,
2425 }))
2426 }
2427}
2428
2429struct FillMeasurementProxy {
2434 direction: FillDirection,
2435 fraction: f32,
2436}
2437
2438impl MeasurementProxy for FillMeasurementProxy {
2439 fn measure_proxy(
2440 &self,
2441 _context: &mut dyn ModifierNodeContext,
2442 wrapped: &dyn Measurable,
2443 constraints: Constraints,
2444 ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
2445 let (fill_width, child_min_width, child_max_width) = if self.direction
2447 != FillDirection::Vertical
2448 && constraints.max_width != f32::INFINITY
2449 {
2450 let width = (constraints.max_width * self.fraction)
2451 .round()
2452 .clamp(constraints.min_width, constraints.max_width);
2453 (width, width, width)
2454 } else {
2455 (
2456 constraints.max_width,
2457 constraints.min_width,
2458 constraints.max_width,
2459 )
2460 };
2461
2462 let (fill_height, child_min_height, child_max_height) = if self.direction
2463 != FillDirection::Horizontal
2464 && constraints.max_height != f32::INFINITY
2465 {
2466 let height = (constraints.max_height * self.fraction)
2467 .round()
2468 .clamp(constraints.min_height, constraints.max_height);
2469 (height, height, height)
2470 } else {
2471 (
2472 constraints.max_height,
2473 constraints.min_height,
2474 constraints.max_height,
2475 )
2476 };
2477
2478 let fill_constraints = Constraints {
2479 min_width: child_min_width,
2480 max_width: child_max_width,
2481 min_height: child_min_height,
2482 max_height: child_max_height,
2483 };
2484
2485 let placeable = wrapped.measure(fill_constraints);
2486
2487 let result_width = if self.direction != FillDirection::Vertical
2489 && constraints.max_width != f32::INFINITY
2490 {
2491 fill_width
2492 } else {
2493 placeable.width()
2494 };
2495
2496 let result_height = if self.direction != FillDirection::Horizontal
2497 && constraints.max_height != f32::INFINITY
2498 {
2499 fill_height
2500 } else {
2501 placeable.height()
2502 };
2503
2504 cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
2505 width: result_width,
2506 height: result_height,
2507 })
2508 }
2509
2510 fn min_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2511 wrapped.min_intrinsic_width(height)
2512 }
2513
2514 fn max_intrinsic_width_proxy(&self, wrapped: &dyn Measurable, height: f32) -> f32 {
2515 wrapped.max_intrinsic_width(height)
2516 }
2517
2518 fn min_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2519 wrapped.min_intrinsic_height(width)
2520 }
2521
2522 fn max_intrinsic_height_proxy(&self, wrapped: &dyn Measurable, width: f32) -> f32 {
2523 wrapped.max_intrinsic_height(width)
2524 }
2525}
2526
2527#[derive(Debug, Clone, PartialEq)]
2531pub struct FillElement {
2532 direction: FillDirection,
2533 fraction: f32,
2534}
2535
2536impl FillElement {
2537 pub fn width(fraction: f32) -> Self {
2538 Self {
2539 direction: FillDirection::Horizontal,
2540 fraction,
2541 }
2542 }
2543
2544 pub fn height(fraction: f32) -> Self {
2545 Self {
2546 direction: FillDirection::Vertical,
2547 fraction,
2548 }
2549 }
2550
2551 pub fn size(fraction: f32) -> Self {
2552 Self {
2553 direction: FillDirection::Both,
2554 fraction,
2555 }
2556 }
2557}
2558
2559impl Hash for FillElement {
2560 fn hash<H: Hasher>(&self, state: &mut H) {
2561 self.direction.hash(state);
2562 hash_f32_value(state, self.fraction);
2563 }
2564}
2565
2566impl ModifierNodeElement for FillElement {
2567 type Node = FillNode;
2568
2569 fn create(&self) -> Self::Node {
2570 FillNode::new(self.direction, self.fraction)
2571 }
2572
2573 fn update(&self, node: &mut Self::Node) {
2574 if node.direction != self.direction || node.fraction != self.fraction {
2575 node.direction = self.direction;
2576 node.fraction = self.fraction;
2577 }
2578 }
2579
2580 fn capabilities(&self) -> NodeCapabilities {
2581 NodeCapabilities::LAYOUT
2582 }
2583}
2584
2585#[derive(Debug)]
2591pub struct WeightNode {
2592 weight: f32,
2593 fill: bool,
2594 state: NodeState,
2595}
2596
2597impl WeightNode {
2598 pub fn new(weight: f32, fill: bool) -> Self {
2599 Self {
2600 weight,
2601 fill,
2602 state: NodeState::new(),
2603 }
2604 }
2605
2606 pub fn layout_weight(&self) -> LayoutWeight {
2607 LayoutWeight {
2608 weight: self.weight,
2609 fill: self.fill,
2610 }
2611 }
2612}
2613
2614impl DelegatableNode for WeightNode {
2615 fn node_state(&self) -> &NodeState {
2616 &self.state
2617 }
2618}
2619
2620impl ModifierNode for WeightNode {
2621 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2622 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2623 }
2624}
2625
2626#[derive(Debug, Clone, PartialEq)]
2628pub struct WeightElement {
2629 weight: f32,
2630 fill: bool,
2631}
2632
2633impl WeightElement {
2634 pub fn new(weight: f32, fill: bool) -> Self {
2635 Self { weight, fill }
2636 }
2637}
2638
2639impl Hash for WeightElement {
2640 fn hash<H: Hasher>(&self, state: &mut H) {
2641 hash_f32_value(state, self.weight);
2642 self.fill.hash(state);
2643 }
2644}
2645
2646impl ModifierNodeElement for WeightElement {
2647 type Node = WeightNode;
2648
2649 fn create(&self) -> Self::Node {
2650 WeightNode::new(self.weight, self.fill)
2651 }
2652
2653 fn update(&self, node: &mut Self::Node) {
2654 if node.weight != self.weight || node.fill != self.fill {
2655 node.weight = self.weight;
2656 node.fill = self.fill;
2657 }
2658 }
2659
2660 fn capabilities(&self) -> NodeCapabilities {
2661 NodeCapabilities::LAYOUT
2662 }
2663}
2664
2665#[derive(Debug)]
2671pub struct AlignmentNode {
2672 box_alignment: Option<Alignment>,
2673 column_alignment: Option<HorizontalAlignment>,
2674 row_alignment: Option<VerticalAlignment>,
2675 state: NodeState,
2676}
2677
2678impl AlignmentNode {
2679 pub fn new(
2680 box_alignment: Option<Alignment>,
2681 column_alignment: Option<HorizontalAlignment>,
2682 row_alignment: Option<VerticalAlignment>,
2683 ) -> Self {
2684 Self {
2685 box_alignment,
2686 column_alignment,
2687 row_alignment,
2688 state: NodeState::new(),
2689 }
2690 }
2691
2692 pub fn box_alignment(&self) -> Option<Alignment> {
2693 self.box_alignment
2694 }
2695
2696 pub fn column_alignment(&self) -> Option<HorizontalAlignment> {
2697 self.column_alignment
2698 }
2699
2700 pub fn row_alignment(&self) -> Option<VerticalAlignment> {
2701 self.row_alignment
2702 }
2703}
2704
2705impl DelegatableNode for AlignmentNode {
2706 fn node_state(&self) -> &NodeState {
2707 &self.state
2708 }
2709}
2710
2711impl ModifierNode for AlignmentNode {
2712 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2713 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2714 }
2715}
2716
2717#[derive(Debug, Clone, PartialEq)]
2719pub struct AlignmentElement {
2720 box_alignment: Option<Alignment>,
2721 column_alignment: Option<HorizontalAlignment>,
2722 row_alignment: Option<VerticalAlignment>,
2723}
2724
2725impl AlignmentElement {
2726 pub fn box_alignment(alignment: Alignment) -> Self {
2727 Self {
2728 box_alignment: Some(alignment),
2729 column_alignment: None,
2730 row_alignment: None,
2731 }
2732 }
2733
2734 pub fn column_alignment(alignment: HorizontalAlignment) -> Self {
2735 Self {
2736 box_alignment: None,
2737 column_alignment: Some(alignment),
2738 row_alignment: None,
2739 }
2740 }
2741
2742 pub fn row_alignment(alignment: VerticalAlignment) -> Self {
2743 Self {
2744 box_alignment: None,
2745 column_alignment: None,
2746 row_alignment: Some(alignment),
2747 }
2748 }
2749}
2750
2751impl Hash for AlignmentElement {
2752 fn hash<H: Hasher>(&self, state: &mut H) {
2753 if let Some(alignment) = self.box_alignment {
2754 state.write_u8(1);
2755 hash_alignment(state, alignment);
2756 } else {
2757 state.write_u8(0);
2758 }
2759 if let Some(alignment) = self.column_alignment {
2760 state.write_u8(1);
2761 hash_horizontal_alignment(state, alignment);
2762 } else {
2763 state.write_u8(0);
2764 }
2765 if let Some(alignment) = self.row_alignment {
2766 state.write_u8(1);
2767 hash_vertical_alignment(state, alignment);
2768 } else {
2769 state.write_u8(0);
2770 }
2771 }
2772}
2773
2774impl ModifierNodeElement for AlignmentElement {
2775 type Node = AlignmentNode;
2776
2777 fn create(&self) -> Self::Node {
2778 AlignmentNode::new(
2779 self.box_alignment,
2780 self.column_alignment,
2781 self.row_alignment,
2782 )
2783 }
2784
2785 fn update(&self, node: &mut Self::Node) {
2786 if node.box_alignment != self.box_alignment {
2787 node.box_alignment = self.box_alignment;
2788 }
2789 if node.column_alignment != self.column_alignment {
2790 node.column_alignment = self.column_alignment;
2791 }
2792 if node.row_alignment != self.row_alignment {
2793 node.row_alignment = self.row_alignment;
2794 }
2795 }
2796
2797 fn capabilities(&self) -> NodeCapabilities {
2798 NodeCapabilities::LAYOUT
2799 }
2800}
2801
2802#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2807pub enum IntrinsicAxis {
2808 Width,
2809 Height,
2810}
2811
2812#[derive(Debug)]
2814pub struct IntrinsicSizeNode {
2815 axis: IntrinsicAxis,
2816 size: IntrinsicSize,
2817 state: NodeState,
2818}
2819
2820impl IntrinsicSizeNode {
2821 pub fn new(axis: IntrinsicAxis, size: IntrinsicSize) -> Self {
2822 Self {
2823 axis,
2824 size,
2825 state: NodeState::new(),
2826 }
2827 }
2828
2829 pub fn axis(&self) -> IntrinsicAxis {
2830 self.axis
2831 }
2832
2833 pub fn intrinsic_size(&self) -> IntrinsicSize {
2834 self.size
2835 }
2836}
2837
2838impl DelegatableNode for IntrinsicSizeNode {
2839 fn node_state(&self) -> &NodeState {
2840 &self.state
2841 }
2842}
2843
2844impl ModifierNode for IntrinsicSizeNode {
2845 fn on_attach(&mut self, context: &mut dyn ModifierNodeContext) {
2846 context.invalidate(cranpose_foundation::InvalidationKind::Layout);
2847 }
2848}
2849
2850#[derive(Debug, Clone, PartialEq)]
2852pub struct IntrinsicSizeElement {
2853 axis: IntrinsicAxis,
2854 size: IntrinsicSize,
2855}
2856
2857impl IntrinsicSizeElement {
2858 pub fn width(size: IntrinsicSize) -> Self {
2859 Self {
2860 axis: IntrinsicAxis::Width,
2861 size,
2862 }
2863 }
2864
2865 pub fn height(size: IntrinsicSize) -> Self {
2866 Self {
2867 axis: IntrinsicAxis::Height,
2868 size,
2869 }
2870 }
2871}
2872
2873impl Hash for IntrinsicSizeElement {
2874 fn hash<H: Hasher>(&self, state: &mut H) {
2875 state.write_u8(match self.axis {
2876 IntrinsicAxis::Width => 0,
2877 IntrinsicAxis::Height => 1,
2878 });
2879 state.write_u8(match self.size {
2880 IntrinsicSize::Min => 0,
2881 IntrinsicSize::Max => 1,
2882 });
2883 }
2884}
2885
2886impl ModifierNodeElement for IntrinsicSizeElement {
2887 type Node = IntrinsicSizeNode;
2888
2889 fn create(&self) -> Self::Node {
2890 IntrinsicSizeNode::new(self.axis, self.size)
2891 }
2892
2893 fn update(&self, node: &mut Self::Node) {
2894 if node.axis != self.axis {
2895 node.axis = self.axis;
2896 }
2897 if node.size != self.size {
2898 node.size = self.size;
2899 }
2900 }
2901
2902 fn capabilities(&self) -> NodeCapabilities {
2903 NodeCapabilities::LAYOUT
2904 }
2905}
2906
2907#[cfg(test)]
2908#[path = "tests/modifier_nodes_tests.rs"]
2909mod tests;