Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/elements/drag/drop_target.rs
StratoSDK / crates / strato-ui-core / src / elements / drag / drop_target.rs
1use crate::elements::Point;
2use crate::event::DispatchedEvent;
3use crate::{AppContext, Element, EventContext, LayoutContext, PaintContext, SizeConstraint};
4use ordered_float::OrderedFloat;
5use pathfinder_geometry::rect::RectF;
6use pathfinder_geometry::vector::Vector2F;
7use std::any::Any;
8use std::fmt::Debug;
9 
10use std::sync::Arc;
11 
12/// Trait to identify data that is passed to a [`crate::elements::Draggable`] when dropped on
13/// a [`DropTarget`].
14pub trait DropTargetData: Debug + Any {
15 fn as_any(&self) -> &dyn Any;
16}
17 
18/// Position for a [`DropTarget`] with the data should be passed to the
19/// [`crate::elements::Draggable`] when dropped.
20#[derive(Clone, Debug)]
21pub(crate) struct DropTargetPosition {
22 bounds: RectF,
23 drop_data: Arc<dyn DropTargetData>,
24}
25 
26impl DropTargetPosition {
27 pub fn bounds(&self) -> RectF {
28 self.bounds
29 }
30 
31 pub fn data(&self) -> &Arc<dyn DropTargetData> {
32 &self.drop_data
33 }
34 
35 /// Returns the area encompassed by this drop target position.
36 pub fn area(&self) -> OrderedFloat<f32> {
37 OrderedFloat::from(self.bounds.width() * self.bounds.height())
38 }
39}
40 
41/// An element that marks whether a [`crate::elements::Draggable`] was dropped on top of it.
42///
43/// Each `DropTarget` is instantiated with data that implements the [`DropTargetData`] trait. When
44/// an item is dropped on the `DropTarget`, the `Draggable` includes the data in the `on_drop`
45/// callback.
46pub struct DropTarget {
47 child: Box<dyn Element>,
48 data: Arc<dyn DropTargetData>,
49}
50 
51impl DropTarget {
52 pub fn new(child: Box<dyn Element>, data: impl DropTargetData + 'static) -> Self {
53 Self {
54 child,
55 data: Arc::new(data),
56 }
57 }
58}
59 
60impl Element for DropTarget {
61 fn layout(
62 &mut self,
63 constraint: SizeConstraint,
64 ctx: &mut LayoutContext,
65 app: &AppContext,
66 ) -> Vector2F {
67 self.child.layout(constraint, ctx, app)
68 }
69 
70 fn after_layout(&mut self, ctx: &mut crate::AfterLayoutContext, app: &crate::AppContext) {
71 self.child.after_layout(ctx, app)
72 }
73 
74 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) {
75 self.child.paint(origin, ctx, app);
76 
77 let Some(bounds) = self.child.bounds() else {
78 return;
79 };
80 ctx.position_cache
81 .cache_drop_target_position(DropTargetPosition {
82 bounds,
83 drop_data: self.data.clone(),
84 });
85 }
86 
87 fn size(&self) -> Option<Vector2F> {
88 self.child.size()
89 }
90 
91 fn origin(&self) -> Option<Point> {
92 self.child.origin()
93 }
94 
95 fn dispatch_event(
96 &mut self,
97 event: &DispatchedEvent,
98 ctx: &mut EventContext,
99 app: &AppContext,
100 ) -> bool {
101 self.child.dispatch_event(event, ctx, app)
102 }
103}
104