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