mac.rs

  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}