1use cocoa::{
2 appkit::NSWindow,
3 base::id,
4 foundation::{NSPoint, NSRect, NSSize},
5};
6use objc::{msg_send, sel, sel_impl};
7use pathfinder_geometry::{
8 rect::RectF,
9 vector::{vec2f, Vector2F},
10};
11
12///! Macos screen have a y axis that goings up from the bottom of the screen and
13///! an origin at the bottom left of the main display.
14
15pub trait Vector2FExt {
16 /// Converts self to an NSPoint with y axis pointing up.
17 fn to_screen_ns_point(&self, native_window: id, window_height: f64) -> NSPoint;
18}
19impl Vector2FExt for Vector2F {
20 fn to_screen_ns_point(&self, native_window: id, window_height: f64) -> NSPoint {
21 unsafe {
22 let point = NSPoint::new(self.x() as f64, window_height - self.y() as f64);
23 msg_send![native_window, convertPointToScreen: point]
24 }
25 }
26}
27
28pub trait RectFExt {
29 /// Converts self to an NSRect with y axis pointing up.
30 /// The resulting NSRect will have an origin at the bottom left of the rectangle.
31 /// Also takes care of converting from window scaled coordinates to screen coordinates
32 fn to_screen_ns_rect(&self, native_window: id) -> NSRect;
33
34 /// Converts self to an NSRect with y axis point up.
35 /// The resulting NSRect will have an origin at the bottom left of the rectangle.
36 /// Unlike to_screen_ns_rect, coordinates are not converted and are assumed to already be in screen scale
37 fn to_ns_rect(&self) -> NSRect;
38}
39impl RectFExt for RectF {
40 fn to_screen_ns_rect(&self, native_window: id) -> NSRect {
41 unsafe { native_window.convertRectToScreen_(self.to_ns_rect()) }
42 }
43
44 fn to_ns_rect(&self) -> NSRect {
45 NSRect::new(
46 NSPoint::new(
47 self.origin_x() as f64,
48 -(self.origin_y() + self.height()) as f64,
49 ),
50 NSSize::new(self.width() as f64, self.height() as f64),
51 )
52 }
53}
54
55pub trait NSRectExt {
56 /// Converts self to a RectF with y axis pointing down.
57 /// The resulting RectF will have an origin at the top left of the rectangle.
58 /// Also takes care of converting from screen scale coordinates to window coordinates
59 fn to_window_rectf(&self, native_window: id) -> RectF;
60
61 /// Converts self to a RectF with y axis pointing down.
62 /// The resulting RectF will have an origin at the top left of the rectangle.
63 /// Unlike to_screen_ns_rect, coordinates are not converted and are assumed to already be in screen scale
64 fn to_rectf(&self) -> RectF;
65
66 fn intersects(&self, other: Self) -> bool;
67}
68impl NSRectExt for NSRect {
69 fn to_window_rectf(&self, native_window: id) -> RectF {
70 unsafe {
71 self.origin.x;
72 let rect: NSRect = native_window.convertRectFromScreen_(*self);
73 rect.to_rectf()
74 }
75 }
76
77 fn to_rectf(&self) -> RectF {
78 RectF::new(
79 vec2f(
80 self.origin.x as f32,
81 -(self.origin.y + self.size.height) as f32,
82 ),
83 vec2f(self.size.width as f32, self.size.height as f32),
84 )
85 }
86
87 fn intersects(&self, other: Self) -> bool {
88 self.size.width > 0.
89 && self.size.height > 0.
90 && other.size.width > 0.
91 && other.size.height > 0.
92 && self.origin.x <= other.origin.x + other.size.width
93 && self.origin.x + self.size.width >= other.origin.x
94 && self.origin.y <= other.origin.y + other.size.height
95 && self.origin.y + self.size.height >= other.origin.y
96 }
97}