1pub use crate::drag::{DragDelta, OptionDragDelta};
9
10#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
12#[repr(C)]
13pub struct LogicalRect {
14 pub origin: LogicalPosition,
15 pub size: LogicalSize,
16}
17
18impl core::fmt::Debug for LogicalRect {
19 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
20 write!(f, "{} @ {}", self.size, self.origin)
21 }
22}
23
24impl core::fmt::Display for LogicalRect {
25 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
26 write!(f, "{} @ {}", self.size, self.origin)
27 }
28}
29
30impl LogicalRect {
31 pub const fn zero() -> Self {
32 Self::new(LogicalPosition::zero(), LogicalSize::zero())
33 }
34 pub const fn new(origin: LogicalPosition, size: LogicalSize) -> Self {
35 Self { origin, size }
36 }
37
38 #[inline]
40 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
41 self.origin.x *= scale_factor;
42 self.origin.y *= scale_factor;
43 self.size.width *= scale_factor;
44 self.size.height *= scale_factor;
45 }
46
47 #[inline(always)]
49 pub fn max_x(&self) -> f32 {
50 self.origin.x + self.size.width
51 }
52 #[inline(always)]
54 pub fn min_x(&self) -> f32 {
55 self.origin.x
56 }
57 #[inline(always)]
59 pub fn max_y(&self) -> f32 {
60 self.origin.y + self.size.height
61 }
62 #[inline(always)]
64 pub fn min_y(&self) -> f32 {
65 self.origin.y
66 }
67
68 #[inline]
70 pub fn intersects(&self, other: Self) -> bool {
71 if self.max_x() <= other.min_x() || other.max_x() <= self.min_x() {
73 return false;
74 }
75
76 if self.max_y() <= other.min_y() || other.max_y() <= self.min_y() {
78 return false;
79 }
80
81 true
83 }
84
85 #[inline]
87 pub fn contains(&self, point: LogicalPosition) -> bool {
88 point.x >= self.min_x()
89 && point.x < self.max_x()
90 && point.y >= self.min_y()
91 && point.y < self.max_y()
92 }
93
94 #[inline]
98 pub fn hit_test(&self, other: &LogicalPosition) -> Option<LogicalPosition> {
99 let dx_left_edge = other.x - self.min_x();
100 let dx_right_edge = self.max_x() - other.x;
101 let dy_top_edge = other.y - self.min_y();
102 let dy_bottom_edge = self.max_y() - other.y;
103 if dx_left_edge > 0.0 && dx_right_edge > 0.0 && dy_top_edge > 0.0 && dy_bottom_edge > 0.0 {
104 Some(LogicalPosition::new(dx_left_edge, dy_top_edge))
105 } else {
106 None
107 }
108 }
109
110}
111
112impl_vec!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor, LogicalRectVecDestructorType, LogicalRectVecSlice, OptionLogicalRect);
113impl_vec_clone!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor);
114impl_vec_debug!(LogicalRect, LogicalRectVec);
115impl_vec_partialeq!(LogicalRect, LogicalRectVec);
116impl_vec_partialord!(LogicalRect, LogicalRectVec);
117impl_vec_ord!(LogicalRect, LogicalRectVec);
118impl_vec_hash!(LogicalRect, LogicalRectVec);
119impl_vec_eq!(LogicalRect, LogicalRectVec);
120
121use core::{
122 cmp::Ordering,
123 hash::{Hash, Hasher},
124 ops::{self, AddAssign, SubAssign},
125};
126
127use azul_css::props::layout::LayoutWritingMode;
128
129#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
131#[repr(C)]
132pub struct LogicalPosition {
133 pub x: f32,
134 pub y: f32,
135}
136
137impl LogicalPosition {
138 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
140 self.x *= scale_factor;
141 self.y *= scale_factor;
142 }
143}
144
145impl SubAssign<LogicalPosition> for LogicalPosition {
146 fn sub_assign(&mut self, other: LogicalPosition) {
147 self.x -= other.x;
148 self.y -= other.y;
149 }
150}
151
152impl AddAssign<LogicalPosition> for LogicalPosition {
153 fn add_assign(&mut self, other: LogicalPosition) {
154 self.x += other.x;
155 self.y += other.y;
156 }
157}
158
159impl core::fmt::Debug for LogicalPosition {
160 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
161 write!(f, "({}, {})", self.x, self.y)
162 }
163}
164
165impl core::fmt::Display for LogicalPosition {
166 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
167 write!(f, "({}, {})", self.x, self.y)
168 }
169}
170
171impl ops::Add for LogicalPosition {
172 type Output = Self;
173
174 #[inline]
175 fn add(self, other: Self) -> Self {
176 Self {
177 x: self.x + other.x,
178 y: self.y + other.y,
179 }
180 }
181}
182
183impl ops::Sub for LogicalPosition {
184 type Output = Self;
185
186 #[inline]
187 fn sub(self, other: Self) -> Self {
188 Self {
189 x: self.x - other.x,
190 y: self.y - other.y,
191 }
192 }
193}
194
195const DECIMAL_MULTIPLIER: f32 = 1000.0;
198
199impl_option!(
200 LogicalPosition,
201 OptionLogicalPosition,
202 [Debug, Copy, Clone, PartialEq, PartialOrd]
203);
204
205impl Ord for LogicalPosition {
206 fn cmp(&self, other: &LogicalPosition) -> Ordering {
207 let self_x = (self.x * DECIMAL_MULTIPLIER) as isize;
208 let self_y = (self.y * DECIMAL_MULTIPLIER) as isize;
209 let other_x = (other.x * DECIMAL_MULTIPLIER) as isize;
210 let other_y = (other.y * DECIMAL_MULTIPLIER) as isize;
211 self_x.cmp(&other_x).then(self_y.cmp(&other_y))
212 }
213}
214
215impl Eq for LogicalPosition {}
216
217impl Hash for LogicalPosition {
218 fn hash<H>(&self, state: &mut H)
219 where
220 H: Hasher,
221 {
222 let self_x = (self.x * DECIMAL_MULTIPLIER) as isize;
223 let self_y = (self.y * DECIMAL_MULTIPLIER) as isize;
224 self_x.hash(state);
225 self_y.hash(state);
226 }
227}
228
229impl LogicalPosition {
230 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
232 match wm {
233 LayoutWritingMode::HorizontalTb => self.y,
234 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.x,
235 }
236 }
237
238 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
240 match wm {
241 LayoutWritingMode::HorizontalTb => self.x,
242 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.y,
243 }
244 }
245
246 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
248 match wm {
249 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
250 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
251 }
252 }
253}
254
255#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
257#[repr(C)]
258pub struct LogicalSize {
259 pub width: f32,
260 pub height: f32,
261}
262
263impl LogicalSize {
264 pub fn scale_for_dpi(&mut self, scale_factor: f32) -> Self {
266 self.width *= scale_factor;
267 self.height *= scale_factor;
268 *self
269 }
270
271 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
273 match wm {
274 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
275 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
276 }
277 }
278}
279
280impl core::fmt::Debug for LogicalSize {
281 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
282 write!(f, "{}x{}", self.width, self.height)
283 }
284}
285
286impl core::fmt::Display for LogicalSize {
287 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
288 write!(f, "{}x{}", self.width, self.height)
289 }
290}
291
292impl_option!(
293 LogicalSize,
294 OptionLogicalSize,
295 [Debug, Copy, Clone, PartialEq, PartialOrd]
296);
297
298impl_option!(
299 LogicalRect,
300 OptionLogicalRect,
301 [Debug, Copy, Clone, PartialEq, PartialOrd]
302);
303
304impl Ord for LogicalSize {
305 fn cmp(&self, other: &LogicalSize) -> Ordering {
306 let self_width = (self.width * DECIMAL_MULTIPLIER) as isize;
307 let self_height = (self.height * DECIMAL_MULTIPLIER) as isize;
308 let other_width = (other.width * DECIMAL_MULTIPLIER) as isize;
309 let other_height = (other.height * DECIMAL_MULTIPLIER) as isize;
310 self_width
311 .cmp(&other_width)
312 .then(self_height.cmp(&other_height))
313 }
314}
315
316impl Eq for LogicalSize {}
317
318impl Hash for LogicalSize {
319 fn hash<H>(&self, state: &mut H)
320 where
321 H: Hasher,
322 {
323 let self_width = (self.width * DECIMAL_MULTIPLIER) as isize;
324 let self_height = (self.height * DECIMAL_MULTIPLIER) as isize;
325 self_width.hash(state);
326 self_height.hash(state);
327 }
328}
329
330impl LogicalSize {
331 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
333 match wm {
334 LayoutWritingMode::HorizontalTb => self.height,
335 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.width,
336 }
337 }
338
339 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
341 match wm {
342 LayoutWritingMode::HorizontalTb => self.width,
343 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.height,
344 }
345 }
346
347 pub fn with_main(self, wm: LayoutWritingMode, value: f32) -> Self {
349 match wm {
350 LayoutWritingMode::HorizontalTb => Self {
351 height: value,
352 ..self
353 },
354 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
355 width: value,
356 ..self
357 },
358 }
359 }
360
361 pub fn with_cross(self, wm: LayoutWritingMode, value: f32) -> Self {
363 match wm {
364 LayoutWritingMode::HorizontalTb => Self {
365 width: value,
366 ..self
367 },
368 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
369 height: value,
370 ..self
371 },
372 }
373 }
374}
375
376#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
378#[repr(C)]
379pub struct PhysicalPosition<T> {
380 pub x: T,
381 pub y: T,
382}
383
384impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalPosition<T> {
385 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
386 write!(f, "({}, {})", self.x, self.y)
387 }
388}
389
390pub type PhysicalPositionI32 = PhysicalPosition<i32>;
391impl_option!(
392 PhysicalPositionI32,
393 OptionPhysicalPositionI32,
394 [Debug, Copy, Clone, PartialEq, PartialOrd]
395);
396
397#[derive(Ord, Hash, Eq, Copy, Clone, PartialEq, PartialOrd)]
399#[repr(C)]
400pub struct PhysicalSize<T> {
401 pub width: T,
402 pub height: T,
403}
404
405impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalSize<T> {
406 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
407 write!(f, "{}x{}", self.width, self.height)
408 }
409}
410
411pub type PhysicalSizeU32 = PhysicalSize<u32>;
412impl_option!(
413 PhysicalSizeU32,
414 OptionPhysicalSizeU32,
415 [Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
416);
417pub type PhysicalSizeF32 = PhysicalSize<f32>;
418impl_option!(
419 PhysicalSizeF32,
420 OptionPhysicalSizeF32,
421 [Debug, Copy, Clone, PartialEq, PartialOrd]
422);
423
424impl LogicalPosition {
425 #[inline(always)]
426 pub const fn new(x: f32, y: f32) -> Self {
427 Self { x, y }
428 }
429 #[inline(always)]
430 pub const fn zero() -> Self {
431 Self::new(0.0, 0.0)
432 }
433 #[inline(always)]
435 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalPosition<u32> {
436 PhysicalPosition {
437 x: libm::roundf(self.x * hidpi_factor) as u32,
438 y: libm::roundf(self.y * hidpi_factor) as u32,
439 }
440 }
441}
442
443impl<T> PhysicalPosition<T> {
444 #[inline(always)]
445 pub const fn new(x: T, y: T) -> Self {
446 Self { x, y }
447 }
448}
449
450impl PhysicalPosition<i32> {
451 #[inline(always)]
452 pub const fn zero() -> Self {
453 Self::new(0, 0)
454 }
455 #[inline(always)]
457 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
458 LogicalPosition {
459 x: self.x as f32 / hidpi_factor,
460 y: self.y as f32 / hidpi_factor,
461 }
462 }
463}
464
465impl PhysicalPosition<f64> {
466 #[inline(always)]
467 pub const fn zero() -> Self {
468 Self::new(0.0, 0.0)
469 }
470 #[inline(always)]
472 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
473 LogicalPosition {
474 x: self.x as f32 / hidpi_factor,
475 y: self.y as f32 / hidpi_factor,
476 }
477 }
478}
479
480impl LogicalSize {
481 #[inline(always)]
482 pub const fn new(width: f32, height: f32) -> Self {
483 Self { width, height }
484 }
485 #[inline(always)]
486 pub const fn zero() -> Self {
487 Self::new(0.0, 0.0)
488 }
489 #[inline(always)]
491 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalSize<u32> {
492 PhysicalSize {
493 width: libm::roundf(self.width * hidpi_factor) as u32,
494 height: libm::roundf(self.height * hidpi_factor) as u32,
495 }
496 }
497}
498
499impl<T> PhysicalSize<T> {
500 #[inline(always)]
501 pub const fn new(width: T, height: T) -> Self {
502 Self { width, height }
503 }
504}
505
506impl PhysicalSize<u32> {
507 #[inline(always)]
508 pub const fn zero() -> Self {
509 Self::new(0, 0)
510 }
511 #[inline(always)]
513 pub fn to_logical(self, hidpi_factor: f32) -> LogicalSize {
514 LogicalSize {
515 width: self.width as f32 / hidpi_factor,
516 height: self.height as f32 / hidpi_factor,
517 }
518 }
519}
520
521#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
531#[repr(C)]
532pub enum CoordinateSpace {
533 Window,
536
537 ScrollFrame,
540
541 Parent,
543
544 ReferenceFrame,
546}
547
548
549#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
556#[repr(C)]
557pub struct ScreenPosition {
558 pub x: f32,
559 pub y: f32,
560}
561
562impl ScreenPosition {
563 #[inline(always)]
564 pub const fn new(x: f32, y: f32) -> Self {
565 Self { x, y }
566 }
567 #[inline(always)]
568 pub const fn zero() -> Self {
569 Self::new(0.0, 0.0)
570 }
571 #[inline(always)]
573 pub const fn to_logical(self) -> LogicalPosition {
574 LogicalPosition { x: self.x, y: self.y }
575 }
576 #[inline(always)]
578 pub const fn from_logical(p: LogicalPosition) -> Self {
579 Self { x: p.x, y: p.y }
580 }
581}
582
583impl_option!(
584 ScreenPosition,
585 OptionScreenPosition,
586 [Debug, Copy, Clone, PartialEq, PartialOrd]
587);
588
589#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
591#[repr(C)]
592pub struct CursorNodePosition {
593 pub x: f32,
594 pub y: f32,
595}
596
597impl CursorNodePosition {
598 #[inline(always)]
599 pub const fn new(x: f32, y: f32) -> Self {
600 Self { x, y }
601 }
602 #[inline(always)]
603 pub const fn zero() -> Self {
604 Self::new(0.0, 0.0)
605 }
606 #[inline(always)]
607 pub const fn to_logical(self) -> LogicalPosition {
608 LogicalPosition { x: self.x, y: self.y }
609 }
610 #[inline(always)]
611 pub const fn from_logical(p: LogicalPosition) -> Self {
612 Self { x: p.x, y: p.y }
613 }
614}
615
616impl_option!(
617 CursorNodePosition,
618 OptionCursorNodePosition,
619 [Debug, Copy, Clone, PartialEq, PartialOrd]
620);