1#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2#[repr(C)]
3pub struct LogicalRect {
4 pub origin: LogicalPosition,
5 pub size: LogicalSize,
6}
7
8impl core::fmt::Debug for LogicalRect {
9 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
10 write!(f, "{} @ {}", self.size, self.origin)
11 }
12}
13
14impl core::fmt::Display for LogicalRect {
15 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
16 write!(f, "{} @ {}", self.size, self.origin)
17 }
18}
19
20impl LogicalRect {
21 pub const fn zero() -> Self {
22 Self::new(LogicalPosition::zero(), LogicalSize::zero())
23 }
24 pub const fn new(origin: LogicalPosition, size: LogicalSize) -> Self {
25 Self { origin, size }
26 }
27
28 #[inline]
29 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
30 self.origin.x *= scale_factor;
31 self.origin.y *= scale_factor;
32 self.size.width *= scale_factor;
33 self.size.height *= scale_factor;
34 }
35
36 #[inline(always)]
37 pub fn max_x(&self) -> f32 {
38 self.origin.x + self.size.width
39 }
40 #[inline(always)]
41 pub fn min_x(&self) -> f32 {
42 self.origin.x
43 }
44 #[inline(always)]
45 pub fn max_y(&self) -> f32 {
46 self.origin.y + self.size.height
47 }
48 #[inline(always)]
49 pub fn min_y(&self) -> f32 {
50 self.origin.y
51 }
52
53 #[inline]
55 pub fn intersects(&self, other: Self) -> bool {
56 if self.max_x() <= other.min_x() || other.max_x() <= self.min_x() {
58 return false;
59 }
60
61 if self.max_y() <= other.min_y() || other.max_y() <= self.min_y() {
63 return false;
64 }
65
66 true
68 }
69
70 #[inline]
72 pub fn contains(&self, point: LogicalPosition) -> bool {
73 point.x >= self.min_x()
74 && point.x < self.max_x()
75 && point.y >= self.min_y()
76 && point.y < self.max_y()
77 }
78
79 #[inline]
81 pub fn union<I: Iterator<Item = Self>>(mut rects: I) -> Option<Self> {
82 let first = rects.next()?;
83
84 let mut max_width = first.size.width;
85 let mut max_height = first.size.height;
86 let mut min_x = first.origin.x;
87 let mut min_y = first.origin.y;
88
89 while let Some(Self {
90 origin: LogicalPosition { x, y },
91 size: LogicalSize { width, height },
92 }) = rects.next()
93 {
94 let cur_lower_right_x = x + width;
95 let cur_lower_right_y = y + height;
96 max_width = max_width.max(cur_lower_right_x - min_x);
97 max_height = max_height.max(cur_lower_right_y - min_y);
98 min_x = min_x.min(x);
99 min_y = min_y.min(y);
100 }
101
102 Some(Self {
103 origin: LogicalPosition { x: min_x, y: min_y },
104 size: LogicalSize {
105 width: max_width,
106 height: max_height,
107 },
108 })
109 }
110
111 #[inline]
115 pub fn hit_test(&self, other: &LogicalPosition) -> Option<LogicalPosition> {
116 let dx_left_edge = other.x - self.min_x();
117 let dx_right_edge = self.max_x() - other.x;
118 let dy_top_edge = other.y - self.min_y();
119 let dy_bottom_edge = self.max_y() - other.y;
120 if dx_left_edge > 0.0 && dx_right_edge > 0.0 && dy_top_edge > 0.0 && dy_bottom_edge > 0.0 {
121 Some(LogicalPosition::new(dx_left_edge, dy_top_edge))
122 } else {
123 None
124 }
125 }
126
127 pub fn to_layout_rect(&self) -> LayoutRect {
128 LayoutRect {
129 origin: LayoutPoint::new(
130 libm::roundf(self.origin.x) as isize,
131 libm::roundf(self.origin.y) as isize,
132 ),
133 size: LayoutSize::new(
134 libm::roundf(self.size.width) as isize,
135 libm::roundf(self.size.height) as isize,
136 ),
137 }
138 }
139}
140
141impl_vec!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor, LogicalRectVecDestructorType, LogicalRectVecSlice, OptionLogicalRect);
142impl_vec_clone!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor);
143impl_vec_debug!(LogicalRect, LogicalRectVec);
144impl_vec_partialeq!(LogicalRect, LogicalRectVec);
145impl_vec_partialord!(LogicalRect, LogicalRectVec);
146impl_vec_ord!(LogicalRect, LogicalRectVec);
147impl_vec_hash!(LogicalRect, LogicalRectVec);
148impl_vec_eq!(LogicalRect, LogicalRectVec);
149
150use core::{
151 cmp::Ordering,
152 hash::{Hash, Hasher},
153 ops::{self, AddAssign, SubAssign},
154};
155
156use azul_css::props::{
157 basic::{LayoutPoint, LayoutRect, LayoutSize},
158 layout::LayoutWritingMode,
159};
160
161#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
162#[repr(C)]
163pub struct LogicalPosition {
164 pub x: f32,
165 pub y: f32,
166}
167
168impl LogicalPosition {
169 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
170 self.x *= scale_factor;
171 self.y *= scale_factor;
172 }
173}
174
175impl SubAssign<LogicalPosition> for LogicalPosition {
176 fn sub_assign(&mut self, other: LogicalPosition) {
177 self.x -= other.x;
178 self.y -= other.y;
179 }
180}
181
182impl AddAssign<LogicalPosition> for LogicalPosition {
183 fn add_assign(&mut self, other: LogicalPosition) {
184 self.x += other.x;
185 self.y += other.y;
186 }
187}
188
189impl core::fmt::Debug for LogicalPosition {
190 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
191 write!(f, "({}, {})", self.x, self.y)
192 }
193}
194
195impl core::fmt::Display for LogicalPosition {
196 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
197 write!(f, "({}, {})", self.x, self.y)
198 }
199}
200
201impl ops::Add for LogicalPosition {
202 type Output = Self;
203
204 #[inline]
205 fn add(self, other: Self) -> Self {
206 Self {
207 x: self.x + other.x,
208 y: self.y + other.y,
209 }
210 }
211}
212
213impl ops::Sub for LogicalPosition {
214 type Output = Self;
215
216 #[inline]
217 fn sub(self, other: Self) -> Self {
218 Self {
219 x: self.x - other.x,
220 y: self.y - other.y,
221 }
222 }
223}
224
225const DECIMAL_MULTIPLIER: f32 = 1000.0;
226
227impl_option!(
228 LogicalPosition,
229 OptionLogicalPosition,
230 [Debug, Copy, Clone, PartialEq, PartialOrd]
231);
232
233impl Ord for LogicalPosition {
234 fn cmp(&self, other: &LogicalPosition) -> Ordering {
235 let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
236 let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
237 let other_x = (other.x * DECIMAL_MULTIPLIER) as usize;
238 let other_y = (other.y * DECIMAL_MULTIPLIER) as usize;
239 self_x.cmp(&other_x).then(self_y.cmp(&other_y))
240 }
241}
242
243impl Eq for LogicalPosition {}
244
245impl Hash for LogicalPosition {
246 fn hash<H>(&self, state: &mut H)
247 where
248 H: Hasher,
249 {
250 let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
251 let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
252 self_x.hash(state);
253 self_y.hash(state);
254 }
255}
256
257impl LogicalPosition {
258 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
259 match wm {
260 LayoutWritingMode::HorizontalTb => self.y,
261 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.x,
262 }
263 }
264
265 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
266 match wm {
267 LayoutWritingMode::HorizontalTb => self.x,
268 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.y,
269 }
270 }
271
272 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
274 match wm {
275 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
276 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
277 }
278 }
279}
280
281#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
282#[repr(C)]
283pub struct LogicalSize {
284 pub width: f32,
285 pub height: f32,
286}
287
288impl LogicalSize {
289 pub fn scale_for_dpi(&mut self, scale_factor: f32) -> Self {
290 self.width *= scale_factor;
291 self.height *= scale_factor;
292 *self
293 }
294
295 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
297 match wm {
298 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
299 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
300 }
301 }
302}
303
304impl core::fmt::Debug for LogicalSize {
305 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
306 write!(f, "{}x{}", self.width, self.height)
307 }
308}
309
310impl core::fmt::Display for LogicalSize {
311 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
312 write!(f, "{}x{}", self.width, self.height)
313 }
314}
315
316impl_option!(
317 LogicalSize,
318 OptionLogicalSize,
319 [Debug, Copy, Clone, PartialEq, PartialOrd]
320);
321
322impl_option!(
323 LogicalRect,
324 OptionLogicalRect,
325 [Debug, Copy, Clone, PartialEq, PartialOrd]
326);
327
328impl Ord for LogicalSize {
329 fn cmp(&self, other: &LogicalSize) -> Ordering {
330 let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
331 let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
332 let other_width = (other.width * DECIMAL_MULTIPLIER) as usize;
333 let other_height = (other.height * DECIMAL_MULTIPLIER) as usize;
334 self_width
335 .cmp(&other_width)
336 .then(self_height.cmp(&other_height))
337 }
338}
339
340impl Eq for LogicalSize {}
341
342impl Hash for LogicalSize {
343 fn hash<H>(&self, state: &mut H)
344 where
345 H: Hasher,
346 {
347 let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
348 let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
349 self_width.hash(state);
350 self_height.hash(state);
351 }
352}
353
354impl LogicalSize {
355 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
356 match wm {
357 LayoutWritingMode::HorizontalTb => self.height,
358 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.width,
359 }
360 }
361
362 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
363 match wm {
364 LayoutWritingMode::HorizontalTb => self.width,
365 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.height,
366 }
367 }
368
369 pub fn with_main(self, wm: LayoutWritingMode, value: f32) -> Self {
371 match wm {
372 LayoutWritingMode::HorizontalTb => Self {
373 height: value,
374 ..self
375 },
376 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
377 width: value,
378 ..self
379 },
380 }
381 }
382
383 pub fn with_cross(self, wm: LayoutWritingMode, value: f32) -> Self {
384 match wm {
385 LayoutWritingMode::HorizontalTb => Self {
386 width: value,
387 ..self
388 },
389 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
390 height: value,
391 ..self
392 },
393 }
394 }
395}
396
397#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
398#[repr(C)]
399pub struct PhysicalPosition<T> {
400 pub x: T,
401 pub y: T,
402}
403
404impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalPosition<T> {
405 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
406 write!(f, "({}, {})", self.x, self.y)
407 }
408}
409
410pub type PhysicalPositionI32 = PhysicalPosition<i32>;
411impl_option!(
412 PhysicalPositionI32,
413 OptionPhysicalPositionI32,
414 [Debug, Copy, Clone, PartialEq, PartialOrd]
415);
416
417#[derive(Ord, Hash, Eq, Copy, Clone, PartialEq, PartialOrd)]
418#[repr(C)]
419pub struct PhysicalSize<T> {
420 pub width: T,
421 pub height: T,
422}
423
424impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalSize<T> {
425 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
426 write!(f, "{}x{}", self.width, self.height)
427 }
428}
429
430pub type PhysicalSizeU32 = PhysicalSize<u32>;
431impl_option!(
432 PhysicalSizeU32,
433 OptionPhysicalSizeU32,
434 [Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
435);
436pub type PhysicalSizeF32 = PhysicalSize<f32>;
437impl_option!(
438 PhysicalSizeF32,
439 OptionPhysicalSizeF32,
440 [Debug, Copy, Clone, PartialEq, PartialOrd]
441);
442
443impl LogicalPosition {
444 #[inline(always)]
445 pub const fn new(x: f32, y: f32) -> Self {
446 Self { x, y }
447 }
448 #[inline(always)]
449 pub const fn zero() -> Self {
450 Self::new(0.0, 0.0)
451 }
452 #[inline(always)]
453 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalPosition<u32> {
454 PhysicalPosition {
455 x: (self.x * hidpi_factor) as u32,
456 y: (self.y * hidpi_factor) as u32,
457 }
458 }
459}
460
461impl<T> PhysicalPosition<T> {
462 #[inline(always)]
463 pub const fn new(x: T, y: T) -> Self {
464 Self { x, y }
465 }
466}
467
468impl PhysicalPosition<i32> {
469 #[inline(always)]
470 pub const fn zero() -> Self {
471 Self::new(0, 0)
472 }
473 #[inline(always)]
474 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
475 LogicalPosition {
476 x: self.x as f32 / hidpi_factor,
477 y: self.y as f32 / hidpi_factor,
478 }
479 }
480}
481
482impl PhysicalPosition<f64> {
483 #[inline(always)]
484 pub const fn zero() -> Self {
485 Self::new(0.0, 0.0)
486 }
487 #[inline(always)]
488 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
489 LogicalPosition {
490 x: self.x as f32 / hidpi_factor,
491 y: self.y as f32 / hidpi_factor,
492 }
493 }
494}
495
496impl LogicalSize {
497 #[inline(always)]
498 pub const fn new(width: f32, height: f32) -> Self {
499 Self { width, height }
500 }
501 #[inline(always)]
502 pub const fn zero() -> Self {
503 Self::new(0.0, 0.0)
504 }
505 #[inline(always)]
506 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalSize<u32> {
507 PhysicalSize {
508 width: (self.width * hidpi_factor) as u32,
509 height: (self.height * hidpi_factor) as u32,
510 }
511 }
512}
513
514impl<T> PhysicalSize<T> {
515 #[inline(always)]
516 pub const fn new(width: T, height: T) -> Self {
517 Self { width, height }
518 }
519}
520
521impl PhysicalSize<u32> {
522 #[inline(always)]
523 pub const fn zero() -> Self {
524 Self::new(0, 0)
525 }
526 #[inline(always)]
527 pub fn to_logical(self, hidpi_factor: f32) -> LogicalSize {
528 LogicalSize {
529 width: self.width as f32 / hidpi_factor,
530 height: self.height as f32 / hidpi_factor,
531 }
532 }
533}
534
535#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
581#[repr(C)]
582pub enum CoordinateSpace {
583 Window,
586
587 ScrollFrame,
590
591 Parent,
593
594 ReferenceFrame,
596}
597
598impl CoordinateSpace {
599 pub const fn description(&self) -> &'static str {
601 match self {
602 CoordinateSpace::Window => "Absolute window coordinates (layout engine output)",
603 CoordinateSpace::ScrollFrame => "Relative to scroll frame origin (for WebRender scroll nodes)",
604 CoordinateSpace::Parent => "Relative to parent node origin",
605 CoordinateSpace::ReferenceFrame => "Relative to CSS transform origin",
606 }
607 }
608}
609
610#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
617#[repr(C)]
618pub struct ScreenPosition {
619 pub x: f32,
620 pub y: f32,
621}
622
623impl ScreenPosition {
624 #[inline(always)]
625 pub const fn new(x: f32, y: f32) -> Self {
626 Self { x, y }
627 }
628 #[inline(always)]
629 pub const fn zero() -> Self {
630 Self::new(0.0, 0.0)
631 }
632 #[inline(always)]
634 pub const fn to_logical(self) -> LogicalPosition {
635 LogicalPosition { x: self.x, y: self.y }
636 }
637 #[inline(always)]
639 pub const fn from_logical(p: LogicalPosition) -> Self {
640 Self { x: p.x, y: p.y }
641 }
642}
643
644impl_option!(
645 ScreenPosition,
646 OptionScreenPosition,
647 [Debug, Copy, Clone, PartialEq, PartialOrd]
648);
649
650#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
652#[repr(C)]
653pub struct CursorNodePosition {
654 pub x: f32,
655 pub y: f32,
656}
657
658impl CursorNodePosition {
659 #[inline(always)]
660 pub const fn new(x: f32, y: f32) -> Self {
661 Self { x, y }
662 }
663 #[inline(always)]
664 pub const fn zero() -> Self {
665 Self::new(0.0, 0.0)
666 }
667 #[inline(always)]
668 pub const fn to_logical(self) -> LogicalPosition {
669 LogicalPosition { x: self.x, y: self.y }
670 }
671 #[inline(always)]
672 pub const fn from_logical(p: LogicalPosition) -> Self {
673 Self { x: p.x, y: p.y }
674 }
675}
676
677impl_option!(
678 CursorNodePosition,
679 OptionCursorNodePosition,
680 [Debug, Copy, Clone, PartialEq, PartialOrd]
681);
682
683#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
686#[repr(C)]
687pub struct DragDelta {
688 pub dx: f32,
689 pub dy: f32,
690}
691
692impl DragDelta {
693 #[inline(always)]
694 pub const fn new(dx: f32, dy: f32) -> Self {
695 Self { dx, dy }
696 }
697 #[inline(always)]
698 pub const fn zero() -> Self {
699 Self::new(0.0, 0.0)
700 }
701}
702
703impl_option!(
704 DragDelta,
705 OptionDragDelta,
706 [Debug, Copy, Clone, PartialEq, PartialOrd]
707);