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