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