dioxus_dnd/core/world/
joined.rs1use dioxus::prelude::{ReadableExt, WritableExt};
5
6use crate::core::types::{Point, ZoneId};
7
8use super::geometry::{WindowGeometry, WindowKey};
9use super::state::{DndWorld, WindowRecord, ZoneLocation};
10
11pub(crate) struct WorldMembership<T: Clone + 'static>(pub(crate) Option<JoinedWindow<T>>);
16
17impl<T: Clone + 'static> Copy for WorldMembership<T> {}
18impl<T: Clone + 'static> Clone for WorldMembership<T> {
19 fn clone(&self) -> Self {
20 *self
21 }
22}
23
24pub struct JoinedWindow<T: Clone + 'static> {
28 pub world: DndWorld<T>,
29 pub key: WindowKey,
30 pub geometry: WindowGeometry,
31}
32
33impl<T: Clone + 'static> Copy for JoinedWindow<T> {}
34impl<T: Clone + 'static> Clone for JoinedWindow<T> {
35 fn clone(&self) -> Self {
36 *self
37 }
38}
39impl<T: Clone + 'static> PartialEq for JoinedWindow<T> {
40 fn eq(&self, other: &Self) -> bool {
41 self.key == other.key && self.world == other.world
42 }
43}
44
45pub(crate) enum WorldHit {
48 Zone(ZoneLocation),
50 Window,
52 Unresolved,
55}
56
57impl<T: Clone + 'static> JoinedWindow<T> {
58 pub(crate) fn zone_under(&self, client: Point) -> WorldHit {
61 let Some(global) = self.geometry.to_global(client) else {
62 return WorldHit::Unresolved;
63 };
64 let mut global_pointer = self.world.global_pointer;
65 if *global_pointer.peek() != Some(global) {
66 global_pointer.set(Some(global));
67 }
68 let Some((rec, local)) = self.world.resolve_global(global) else {
69 return WorldHit::Unresolved;
70 };
71 match rec.registry.hit_test(local) {
72 Some(zone) => WorldHit::Zone(ZoneLocation {
73 window: rec.key,
74 zone,
75 }),
76 None => WorldHit::Window,
77 }
78 }
79
80 pub fn location(&self, zone: ZoneId) -> ZoneLocation {
82 ZoneLocation {
83 window: self.key,
84 zone,
85 }
86 }
87
88 pub fn enter(&self, location: ZoneLocation) {
91 self.world.enter_location(location);
92 }
93
94 pub fn clear_hover(&self) {
96 self.world.clear_hover();
97 }
98
99 pub fn is_over(&self, zone: ZoneId) -> bool {
101 self.world.over_location() == Some(self.location(zone))
102 }
103
104 pub fn local_pointer(&self) -> Option<Point> {
108 if let Some(local) = self
109 .world
110 .global_pointer()
111 .and_then(|global| self.geometry.to_client(global))
112 {
113 return Some(local);
114 }
115 (self.world.origin_window() == Some(self.key)).then(|| self.world.ctx.pointer())
116 }
117
118 pub(crate) fn foreign_window_under(&self, client: Point) -> Option<(WindowRecord<T>, Point)> {
123 let global = self.geometry.to_global(client)?;
124 let (rec, local) = self.world.resolve_global(global)?;
125 (rec.key != self.key).then_some((rec, local))
126 }
127
128 pub(crate) fn present_overlay(
138 &self,
139 pointer: Point,
140 grab: Point,
141 settling: bool,
142 ) -> Option<(Point, f64)> {
143 let raw = pointer - grab;
144 let Some(active) = self.world.active_drag() else {
145 return Some((raw, 1.0));
148 };
149 let origin = self.world.record(active.origin);
150 let origin_scale = origin
151 .map(|record| record.geometry.scale())
152 .unwrap_or(active.origin_scale);
153 let global_anchor = origin
154 .and_then(|record| record.geometry.to_global(raw))
155 .or_else(|| {
156 self.world.global_pointer().map(|global| {
157 Point::new(
158 global.x - grab.x * origin_scale,
159 global.y - grab.y * origin_scale,
160 )
161 })
162 });
163 let Some(global_anchor) = global_anchor else {
164 return (self.key == active.origin).then_some((raw, 1.0));
166 };
167 let presenting = if settling {
168 self.world.settling_in()?
169 } else {
170 let pointer_global = self
171 .world
172 .global_pointer()
173 .or_else(|| origin.and_then(|record| record.geometry.to_global(pointer)))
174 .unwrap_or(global_anchor);
175 self.world
176 .window_under(pointer_global)
177 .map(|r| r.key)
178 .unwrap_or(active.origin)
179 };
180 if presenting != self.key {
181 return None;
182 }
183 match self.geometry.to_client(global_anchor) {
184 Some(local) => {
185 let own_scale = self.geometry.scale();
186 let ratio = if own_scale > 0.0 {
187 origin_scale / own_scale
188 } else {
189 1.0
190 };
191 Some((local, ratio))
192 }
193 None => (self.key == active.origin).then_some((raw, 1.0)),
195 }
196 }
197}