1//! Macos screen have a y axis that goings up from the bottom of the screen and
2//! an origin at the bottom left of the main display.
3mod dispatcher;
4mod display;
5mod display_link;
6mod events;
7
8#[cfg(not(feature = "macos-blade"))]
9mod metal_atlas;
10#[cfg(not(feature = "macos-blade"))]
11pub mod metal_renderer;
12
13#[cfg(not(feature = "macos-blade"))]
14use metal_renderer as renderer;
15
16#[cfg(feature = "macos-blade")]
17use crate::platform::blade as renderer;
18
19mod attributed_string;
20
21#[cfg(feature = "font-kit")]
22mod open_type;
23
24#[cfg(feature = "font-kit")]
25mod text_system;
26
27mod platform;
28mod window;
29mod window_appearance;
30
31use crate::{px, size, DevicePixels, Pixels, Size};
32use cocoa::{
33 base::{id, nil},
34 foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger},
35};
36
37use objc::runtime::{BOOL, NO, YES};
38use std::{
39 ffi::{c_char, CStr},
40 ops::Range,
41};
42
43pub(crate) use dispatcher::*;
44pub(crate) use display::*;
45pub(crate) use display_link::*;
46pub(crate) use platform::*;
47pub(crate) use window::*;
48
49#[cfg(feature = "font-kit")]
50pub(crate) use text_system::*;
51
52trait BoolExt {
53 fn to_objc(self) -> BOOL;
54}
55
56impl BoolExt for bool {
57 fn to_objc(self) -> BOOL {
58 if self {
59 YES
60 } else {
61 NO
62 }
63 }
64}
65
66trait NSStringExt {
67 unsafe fn to_str(&self) -> &str;
68}
69
70impl NSStringExt for id {
71 unsafe fn to_str(&self) -> &str {
72 let cstr = self.UTF8String();
73 if cstr.is_null() {
74 ""
75 } else {
76 CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
77 }
78 }
79}
80
81#[repr(C)]
82#[derive(Copy, Clone, Debug)]
83struct NSRange {
84 pub location: NSUInteger,
85 pub length: NSUInteger,
86}
87
88impl NSRange {
89 fn invalid() -> Self {
90 Self {
91 location: NSNotFound as NSUInteger,
92 length: 0,
93 }
94 }
95
96 fn is_valid(&self) -> bool {
97 self.location != NSNotFound as NSUInteger
98 }
99
100 fn to_range(self) -> Option<Range<usize>> {
101 if self.is_valid() {
102 let start = self.location as usize;
103 let end = start + self.length as usize;
104 Some(start..end)
105 } else {
106 None
107 }
108 }
109}
110
111impl From<Range<usize>> for NSRange {
112 fn from(range: Range<usize>) -> Self {
113 NSRange {
114 location: range.start as NSUInteger,
115 length: range.len() as NSUInteger,
116 }
117 }
118}
119
120unsafe impl objc::Encode for NSRange {
121 fn encode() -> objc::Encoding {
122 let encoding = format!(
123 "{{NSRange={}{}}}",
124 NSUInteger::encode().as_str(),
125 NSUInteger::encode().as_str()
126 );
127 unsafe { objc::Encoding::from_str(&encoding) }
128 }
129}
130
131unsafe fn ns_string(string: &str) -> id {
132 NSString::alloc(nil).init_str(string).autorelease()
133}
134
135impl From<NSSize> for Size<Pixels> {
136 fn from(value: NSSize) -> Self {
137 Size {
138 width: px(value.width as f32),
139 height: px(value.height as f32),
140 }
141 }
142}
143
144impl From<NSRect> for Size<Pixels> {
145 fn from(rect: NSRect) -> Self {
146 let NSSize { width, height } = rect.size;
147 size(width.into(), height.into())
148 }
149}
150
151impl From<NSRect> for Size<DevicePixels> {
152 fn from(rect: NSRect) -> Self {
153 let NSSize { width, height } = rect.size;
154 size(DevicePixels(width as i32), DevicePixels(height as i32))
155 }
156}