diff --git a/cocoa/Cargo.toml b/cocoa/Cargo.toml index 409f28b..d4ee5b5 100644 --- a/cocoa/Cargo.toml +++ b/cocoa/Cargo.toml @@ -16,5 +16,7 @@ crate-type = ["rlib"] block = "0.1" bitflags = "1.0" libc = "0.2" +core-foundation = { path = "../core-foundation", version = "0.6" } core-graphics = { path = "../core-graphics", version = "0.17" } +foreign-types = "0.3" objc = "0.2.3" diff --git a/cocoa/src/lib.rs b/cocoa/src/lib.rs index 9cdffbc..179c0d3 100644 --- a/cocoa/src/lib.rs +++ b/cocoa/src/lib.rs @@ -15,8 +15,10 @@ extern crate block; #[macro_use] extern crate bitflags; -extern crate libc; +extern crate core_foundation; extern crate core_graphics; +extern crate foreign_types; +extern crate libc; #[macro_use] extern crate objc; @@ -24,3 +26,5 @@ extern crate objc; pub mod appkit; pub mod base; pub mod foundation; +#[cfg(target_os = "macos")] +pub mod quartzcore; diff --git a/cocoa/src/quartzcore.rs b/cocoa/src/quartzcore.rs new file mode 100644 index 0000000..b3420c4 --- /dev/null +++ b/cocoa/src/quartzcore.rs @@ -0,0 +1,1587 @@ +// Copyright 2018 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::array::{CFArray, CFArrayRef}; +use core_foundation::base::{CFTypeRef, TCFType}; +use core_foundation::date::CFTimeInterval; +use core_foundation::dictionary::{CFDictionary, CFDictionaryRef}; +use core_foundation::string::{CFString, CFStringRef}; +use core_graphics::base::CGFloat; +use core_graphics::color::{CGColor, SysCGColorRef}; +use core_graphics::context::CGContext; +use core_graphics::geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; +use core_graphics::path::{CGPath, SysCGPathRef}; +use foreign_types::ForeignType; +use std::ops::Mul; +use std::ptr; + +use base::{BOOL, id, nil, YES}; +use foundation::NSUInteger; + +// CALayer.h + +pub struct CALayer(id); + +unsafe impl Send for CALayer {} +unsafe impl Sync for CALayer {} + +impl Clone for CALayer { + #[inline] + fn clone(&self) -> CALayer { + unsafe { + CALayer(msg_send![self.id(), retain]) + } + } +} + +impl Drop for CALayer { + #[inline] + fn drop(&mut self) { + unsafe { + msg_send![self.id(), release] + } + } +} + +impl CALayer { + #[inline] + pub fn id(&self) -> id { + self.0 + } + + #[inline] + pub fn new() -> CALayer { + unsafe { + CALayer(msg_send![class!(CALayer), layer]) + } + } + + #[inline] + pub fn from_layer(other: &CALayer) -> CALayer { + unsafe { + let layer: id = msg_send![class!(CALayer), alloc]; + CALayer(msg_send![layer, initWithLayer:other.id()]) + } + } + + #[inline] + pub fn presentation_layer(&self) -> CALayer { + unsafe { + CALayer(msg_send![self.id(), presentationLayer]) + } + } + + #[inline] + pub fn model_layer(&self) -> CALayer { + unsafe { + CALayer(msg_send![self.id(), modelLayer]) + } + } + + #[inline] + pub fn default_value_for_key(key: &CFString) -> id { + unsafe { + msg_send![class!(CALayer), defaultValueForKey:(key.as_CFTypeRef())] + } + } + + #[inline] + pub fn needs_display_for_key(key: &CFString) -> bool { + unsafe { + let flag: BOOL = msg_send![class!(CALayer), needsDisplayForKey:(key.as_CFTypeRef())]; + flag == YES + } + } + + #[inline] + pub fn should_archive_value_for_key(key: &CFString) -> bool { + unsafe { + let flag: BOOL = msg_send![class!(CALayer), shouldArchiveValueForKey:(key.as_CFTypeRef())]; + flag == YES + } + } + + #[inline] + pub fn bounds(&self) -> CGRect { + unsafe { + msg_send![self.id(), bounds] + } + } + + #[inline] + pub fn set_bounds(&self, bounds: &CGRect) { + unsafe { + msg_send![self.id(), setBounds:*bounds] + } + } + + #[inline] + pub fn position(&self) -> CGPoint { + unsafe { + msg_send![self.id(), position] + } + } + + #[inline] + pub fn set_position(&self, position: &CGPoint) { + unsafe { + msg_send![self.id(), setPosition:*position] + } + } + + #[inline] + pub fn z_position(&self) -> CGFloat { + unsafe { + msg_send![self.id(), zPosition] + } + } + + #[inline] + pub fn set_z_position(&self, z_position: CGFloat) { + unsafe { + msg_send![self.id(), setZPosition:z_position] + } + } + + #[inline] + pub fn anchor_point(&self) -> CGPoint { + unsafe { + msg_send![self.id(), anchorPoint] + } + } + + #[inline] + pub fn set_anchor_point(&self, anchor_point: &CGPoint) { + unsafe { + msg_send![self.id(), setAnchorPoint:*anchor_point] + } + } + + #[inline] + pub fn anchor_point_z(&self) -> CGFloat { + unsafe { + msg_send![self.id(), anchorPointZ] + } + } + + #[inline] + pub fn set_anchor_point_z(&self, anchor_point_z: CGFloat) { + unsafe { + msg_send![self.id(), setAnchorPointZ:anchor_point_z] + } + } + + #[inline] + pub fn transform(&self) -> CATransform3D { + unsafe { + msg_send![self.id(), transform] + } + } + + #[inline] + pub fn set_transform(&self, transform: &CATransform3D) { + unsafe { + msg_send![self.id(), setTransform:*transform] + } + } + + #[inline] + pub fn affine_transform(&self) -> CGAffineTransform { + unsafe { + msg_send![self.id(), affineTransform] + } + } + + #[inline] + pub fn set_affine_transform(&self, affine_transform: &CGAffineTransform) { + unsafe { + msg_send![self.id(), setAffineTransform:*affine_transform] + } + } + + #[inline] + pub fn frame(&self) -> CGRect { + unsafe { + msg_send![self.id(), frame] + } + } + + #[inline] + pub fn set_frame(&self, frame: &CGRect) { + unsafe { + msg_send![self.id(), setFrame:*frame] + } + } + + #[inline] + pub fn is_hidden(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), isHidden]; + flag == YES + } + } + + #[inline] + pub fn set_hidden(&self, hidden: bool) { + unsafe { + msg_send![self.id(), setHidden:hidden as BOOL] + } + } + + #[inline] + pub fn is_double_sided(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), isDoubleSided]; + flag == YES + } + } + + #[inline] + pub fn set_double_sided(&self, double_sided: bool) { + unsafe { + msg_send![self.id(), setDoubleSided:double_sided as BOOL] + } + } + + #[inline] + pub fn is_geometry_flipped(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), isGeometryFlipped]; + flag == YES + } + } + + #[inline] + pub fn set_geometry_flipped(&self, geometry_flipped: bool) { + unsafe { + msg_send![self.id(), setGeometryFlipped:geometry_flipped as BOOL] + } + } + + #[inline] + pub fn contents_are_flipped(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), contentsAreFlipped]; + flag == YES + } + } + + #[inline] + pub fn superlayer(&self) -> Option { + unsafe { + let superlayer: id = msg_send![self.id(), superlayer]; + if superlayer.is_null() { + None + } else { + Some(CALayer(superlayer)) + } + } + } + + #[inline] + pub fn remove_from_superlayer(&self) { + unsafe { + msg_send![self.id(), removeFromSuperlayer] + } + } + + #[inline] + pub fn sublayers(&self) -> CFArray { + unsafe { + let sublayers: CFArrayRef = msg_send![self.id(), sublayers]; + TCFType::wrap_under_create_rule(sublayers) + } + } + + #[inline] + pub fn insert_sublayer_at_index(&self, sublayer: &CALayer, index: u32) { + unsafe { + msg_send![self.id(), insertSublayer:sublayer.id() atIndex:index] + } + } + + #[inline] + pub fn insert_sublayer_below(&self, sublayer: &CALayer, sibling: &CALayer) { + unsafe { + msg_send![self.id(), insertSublayer:sublayer.id() below:sibling.id()] + } + } + + #[inline] + pub fn insert_sublayer_above(&self, sublayer: &CALayer, sibling: &CALayer) { + unsafe { + msg_send![self.id(), insertSublayer:sublayer.id() above:sibling.id()] + } + } + + #[inline] + pub fn replace_sublayer_with(&self, old_layer: &CALayer, new_layer: &CALayer) { + unsafe { + msg_send![self.id(), replaceSublayer:old_layer.id() with:new_layer.id()] + } + } + + #[inline] + pub fn sublayer_transform(&self) -> CATransform3D { + unsafe { + msg_send![self.id(), sublayerTransform] + } + } + + #[inline] + pub fn set_sublayer_transform(&self, sublayer_transform: CATransform3D) { + unsafe { + msg_send![self.id(), setSublayerTransform:sublayer_transform] + } + } + + #[inline] + pub fn mask(&self) -> Option { + unsafe { + let mask: id = msg_send![self.id(), mask]; + if mask.is_null() { + None + } else { + Some(CALayer(mask)) + } + } + } + + #[inline] + pub fn set_mask(&self, mask: Option) { + unsafe { + match mask { + None => msg_send![self.id(), setMask:nil], + Some(mask) => msg_send![self.id(), setMask:(mask.id())], + } + } + } + + #[inline] + pub fn masks_to_bounds(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), masksToBounds]; + flag == YES + } + } + + #[inline] + pub fn set_masks_to_bounds(&self, flag: bool) { + unsafe { + msg_send![self.id(), setMasksToBounds:flag as BOOL] + } + } + + #[inline] + pub fn convert_point_from_layer(&self, point: &CGPoint, layer: Option) -> CGPoint { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertPoint:*point fromLayer:layer] + } + } + + #[inline] + pub fn convert_point_to_layer(&self, point: &CGPoint, layer: Option) -> CGPoint { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertPoint:*point toLayer:layer] + } + } + + #[inline] + pub fn convert_rect_from_layer(&self, rect: &CGRect, layer: Option) -> CGRect { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertRect:*rect fromLayer:layer] + } + } + + #[inline] + pub fn convert_rect_to_layer(&self, rect: &CGRect, layer: Option) -> CGRect { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertRect:*rect toLayer:layer] + } + } + + #[inline] + pub fn convert_time_from_layer(&self, time: CFTimeInterval, layer: Option) + -> CFTimeInterval { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertTime:time fromLayer:layer] + } + } + + #[inline] + pub fn convert_time_to_layer(&self, time: CFTimeInterval, layer: Option) + -> CFTimeInterval { + unsafe { + let layer = match layer { + None => nil, + Some(ref layer) => layer.id(), + }; + msg_send![self.id(), convertTime:time toLayer:layer] + } + } + + #[inline] + pub fn hit_test(&self, point: &CGPoint) -> Option { + unsafe { + let layer: id = msg_send![self.id(), hitTest:*point]; + if layer == nil { + None + } else { + Some(CALayer(layer)) + } + } + } + + #[inline] + pub fn contains_point(&self, point: &CGPoint) -> bool { + unsafe { + let result: BOOL = msg_send![self.id(), containsPoint:*point]; + result == YES + } + } + + #[inline] + pub fn contents(&self) -> id { + unsafe { + msg_send![self.id(), contents] + } + } + + #[inline] + pub unsafe fn set_contents(&self, contents: id) { + msg_send![self.id(), setContents:contents] + } + + #[inline] + pub fn contents_rect(&self) -> CGRect { + unsafe { + msg_send![self.id(), contentsRect] + } + } + + #[inline] + pub fn set_contents_rect(&self, contents_rect: &CGRect) { + unsafe { + msg_send![self.id(), setContentsRect:*contents_rect] + } + } + + #[inline] + pub fn contents_gravity(&self) -> ContentsGravity { + unsafe { + let string: CFStringRef = msg_send![self.id(), contentsGravity]; + ContentsGravity::from_CFString(TCFType::wrap_under_create_rule(string)) + } + } + + #[inline] + pub fn set_contents_gravity(&self, new_contents_gravity: ContentsGravity) { + unsafe { + let contents_gravity: CFString = new_contents_gravity.into_CFString(); + msg_send![self.id(), setContentsGravity:contents_gravity.as_CFTypeRef()] + } + } + + #[inline] + pub fn contents_scale(&self) -> CGFloat { + unsafe { + msg_send![self.id(), contentsScale] + } + } + + #[inline] + pub fn set_contents_scale(&self, new_contents_scale: CGFloat) { + unsafe { + msg_send![self.id(), setContentsScale:new_contents_scale] + } + } + + #[inline] + pub fn contents_center(&self) -> CGRect { + unsafe { + msg_send![self.id(), contentsCenter] + } + } + + #[inline] + pub fn set_contents_center(&self, new_rect: &CGRect) { + unsafe { + msg_send![self.id(), setContentsCenter:*new_rect] + } + } + + #[inline] + pub fn contents_format(&self) -> ContentsFormat { + unsafe { + let string: CFStringRef = msg_send![self.id(), contentsFormat]; + ContentsFormat::from_CFString(TCFType::wrap_under_create_rule(string)) + } + } + + #[inline] + pub fn set_contents_format(&self, new_contents_format: ContentsFormat) { + unsafe { + let contents_format: CFString = new_contents_format.into_CFString(); + msg_send![self.id(), setContentsFormat:contents_format.as_CFTypeRef()] + } + } + + #[inline] + pub fn minification_filter(&self) -> Filter { + unsafe { + let string: CFStringRef = msg_send![self.id(), minificationFilter]; + Filter::from_CFString(TCFType::wrap_under_create_rule(string)) + } + } + + #[inline] + pub fn set_minification_filter(&self, new_filter: Filter) { + unsafe { + let filter: CFString = new_filter.into_CFString(); + msg_send![self.id(), setMinificationFilter:filter.as_CFTypeRef()] + } + } + + #[inline] + pub fn magnification_filter(&self) -> Filter { + unsafe { + let string: CFStringRef = msg_send![self.id(), magnificationFilter]; + Filter::from_CFString(TCFType::wrap_under_create_rule(string)) + } + } + + #[inline] + pub fn set_magnification_filter(&self, new_filter: Filter) { + unsafe { + let filter: CFString = new_filter.into_CFString(); + msg_send![self.id(), setMagnificationFilter:filter.as_CFTypeRef()] + } + } + + #[inline] + pub fn minification_filter_bias(&self) -> f32 { + unsafe { + msg_send![self.id(), minificationFilterBias] + } + } + + #[inline] + pub fn set_minification_filter_bias(&self, new_filter_bias: f32) { + unsafe { + msg_send![self.id(), setMinificationFilterBias:new_filter_bias] + } + } + + #[inline] + pub fn is_opaque(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), isOpaque]; + flag == YES + } + } + + #[inline] + pub fn set_opaque(&self, opaque: bool) { + unsafe { + msg_send![self.id(), setOpaque:opaque as BOOL] + } + } + + #[inline] + pub fn display(&self) { + unsafe { + msg_send![self.id(), display] + } + } + + #[inline] + pub fn set_needs_display(&self) { + unsafe { + msg_send![self.id(), setNeedsDisplay] + } + } + + #[inline] + pub fn set_needs_display_in_rect(&self, rect: &CGRect) { + unsafe { + msg_send![self.id(), setNeedsDisplayInRect:*rect] + } + } + + #[inline] + pub fn needs_display(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), needsDisplay]; + flag == YES + } + } + + #[inline] + pub fn display_if_needed(&self) { + unsafe { + msg_send![self.id(), displayIfNeeded] + } + } + + #[inline] + pub fn needs_display_on_bounds_change(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), needsDisplayOnBoundsChange]; + flag == YES + } + } + + #[inline] + pub fn set_needs_display_on_bounds_change(&self, flag: bool) { + unsafe { + msg_send![self.id(), setNeedsDisplayOnBoundsChange:flag as BOOL] + } + } + + #[inline] + pub fn draws_asynchronously(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), drawsAsynchronously]; + flag == YES + } + } + + #[inline] + pub fn set_draws_asynchronously(&self, flag: bool) { + unsafe { + msg_send![self.id(), setDrawsAsynchronously:flag as BOOL] + } + } + + #[inline] + pub fn draw_in_context(&self, context: &CGContext) { + unsafe { + msg_send![self.id(), drawInContext:(*context).as_ptr()] + } + } + + #[inline] + pub fn render_in_context(&self, context: &CGContext) { + unsafe { + msg_send![self.id(), renderInContext:(*context).as_ptr()] + } + } + + #[inline] + pub fn edge_antialiasing_mask(&self) -> EdgeAntialiasingMask { + unsafe { + EdgeAntialiasingMask::from_bits_truncate(msg_send![self.id(), edgeAntialiasingMask]) + } + } + + #[inline] + pub fn set_edge_antialiasing_mask(&self, mask: EdgeAntialiasingMask) { + unsafe { + msg_send![self.id(), setEdgeAntialiasingMask:mask.bits()] + } + } + + #[inline] + pub fn background_color(&self) -> Option { + unsafe { + let color: SysCGColorRef = msg_send![self.id(), backgroundColor]; + if color.is_null() { + None + } else { + Some(CGColor::wrap_under_get_rule(color)) + } + } + } + + #[inline] + pub fn set_background_color(&self, color: Option) { + unsafe { + let color = match color { + None => ptr::null(), + Some(color) => color.as_CFTypeRef(), + }; + msg_send![self.id(), setBackgroundColor:color] + } + } + + #[inline] + pub fn corner_radius(&self) -> CGFloat { + unsafe { + msg_send![self.id(), cornerRadius] + } + } + + #[inline] + pub fn set_corner_radius(&self, radius: CGFloat) { + unsafe { + msg_send![self.id(), setCornerRadius:radius] + } + } + + #[inline] + pub fn masked_corners(&self) -> CornerMask { + unsafe { + CornerMask::from_bits_truncate(msg_send![self.id(), maskedCorners]) + } + } + + #[inline] + pub fn set_masked_corners(&self, mask: CornerMask) { + unsafe { + msg_send![self.id(), setCornerMask:mask.bits()] + } + } + + #[inline] + pub fn border_width(&self) -> CGFloat { + unsafe { + msg_send![self.id(), borderWidth] + } + } + + #[inline] + pub fn set_border_width(&self, border_width: CGFloat) { + unsafe { + msg_send![self.id(), setBorderWidth:border_width] + } + } + + #[inline] + pub fn border_color(&self) -> Option { + unsafe { + let color: SysCGColorRef = msg_send![self.id(), borderColor]; + if color.is_null() { + None + } else { + Some(CGColor::wrap_under_get_rule(color)) + } + } + } + + #[inline] + pub fn set_border_color(&self, color: Option) { + unsafe { + let color = match color { + None => ptr::null(), + Some(color) => color.as_CFTypeRef(), + }; + msg_send![self.id(), setBorderColor:color] + } + } + + #[inline] + pub fn opacity(&self) -> f32 { + unsafe { + msg_send![self.id(), opacity] + } + } + + #[inline] + pub fn set_opacity(&self, opacity: f32) { + unsafe { + msg_send![self.id(), setOpacity:opacity] + } + } + + #[inline] + pub fn compositing_filter(&self) -> id { + unsafe { + msg_send![self.id(), compositingFilter] + } + } + + #[inline] + pub unsafe fn set_compositing_filter(&self, filter: id) { + msg_send![self.id(), setCompositingFilter:filter] + } + + #[inline] + pub unsafe fn filters(&self) -> Option { + let filters: CFArrayRef = msg_send![self.id(), filters]; + if filters.is_null() { + None + } else { + Some(CFArray::wrap_under_get_rule(filters)) + } + } + + #[inline] + pub unsafe fn set_filters(&self, filters: Option) { + let filters: CFTypeRef = match filters { + Some(ref filters) => filters.as_CFTypeRef(), + None => ptr::null(), + }; + msg_send![self.id(), setFilters:filters] + } + + #[inline] + pub unsafe fn background_filters(&self) -> Option { + let filters: CFArrayRef = msg_send![self.id(), backgroundFilters]; + if filters.is_null() { + None + } else { + Some(CFArray::wrap_under_get_rule(filters)) + } + } + + #[inline] + pub unsafe fn set_background_filters(&self, filters: Option) { + let filters: CFTypeRef = match filters { + Some(ref filters) => filters.as_CFTypeRef(), + None => ptr::null(), + }; + msg_send![self.id(), setBackgroundFilters:filters] + } + + #[inline] + pub fn should_rasterize(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), shouldRasterize]; + flag == YES + } + } + + #[inline] + pub fn set_should_rasterize(&self, flag: bool) { + unsafe { + msg_send![self.id(), setShouldRasterize:(flag as BOOL)]; + } + } + + #[inline] + pub fn rasterization_scale(&self) -> CGFloat { + unsafe { + msg_send![self.id(), rasterizationScale] + } + } + + #[inline] + pub fn set_rasterization_scale(&self, scale: CGFloat) { + unsafe { + msg_send![self.id(), setRasterizationScale:scale] + } + } + + // Shadow properties + + #[inline] + pub fn shadow_color(&self) -> Option { + unsafe { + let color: SysCGColorRef = msg_send![self.id(), shadowColor]; + if color.is_null() { + None + } else { + Some(CGColor::wrap_under_get_rule(color)) + } + } + } + + #[inline] + pub fn set_shadow_color(&self, color: Option) { + unsafe { + let color = match color { + None => ptr::null(), + Some(color) => color.as_CFTypeRef(), + }; + msg_send![self.id(), setShadowColor:color] + } + } + + #[inline] + pub fn shadow_opacity(&self) -> f32 { + unsafe { + msg_send![self.id(), shadowOpacity] + } + } + + #[inline] + pub fn set_shadow_opacity(&self, opacity: f32) { + unsafe { + msg_send![self.id(), setShadowOpacity:opacity] + } + } + + #[inline] + pub fn shadow_offset(&self) -> CGSize { + unsafe { + msg_send![self.id(), shadowOffset] + } + } + + #[inline] + pub fn set_shadow_offset(&self, offset: &CGSize) { + unsafe { + msg_send![self.id(), setShadowOffset:*offset] + } + } + + #[inline] + pub fn shadow_radius(&self) -> CGFloat { + unsafe { + msg_send![self.id(), shadowRadius] + } + } + + #[inline] + pub fn set_shadow_radius(&self, radius: CGFloat) { + unsafe { + msg_send![self.id(), setShadowRadius:radius] + } + } + + #[inline] + pub fn shadow_path(&self) -> Option { + unsafe { + let path: SysCGPathRef = msg_send![self.id(), shadowPath]; + if path.is_null() { + None + } else { + Some(CGPath::from_ptr(path)) + } + } + } + + #[inline] + pub fn set_shadow_path(&self, path: Option) { + unsafe { + let sys_path_ref = match path { + None => ptr::null(), + Some(path) => path.as_ptr(), + }; + msg_send![self.id(), setShadowPath:sys_path_ref] + } + } + + // Layout methods + + #[inline] + pub fn autoresizing_mask(&self) -> AutoresizingMask { + unsafe { + AutoresizingMask::from_bits_truncate(msg_send![self.id(), autoresizingMask]) + } + } + + #[inline] + pub fn set_autoresizing_mask(&self, mask: AutoresizingMask) { + unsafe { + msg_send![self.id(), setAutoresizingMask:mask.bits()] + } + } + + #[inline] + pub fn layout_manager(&self) -> id { + unsafe { + msg_send![self.id(), layoutManager] + } + } + + #[inline] + pub unsafe fn set_layout_manager(&self, manager: id) { + msg_send![self.id(), setLayoutManager:manager] + } + + #[inline] + pub fn preferred_frame_size(&self) -> CGSize { + unsafe { + msg_send![self.id(), preferredFrameSize] + } + } + + #[inline] + pub fn set_needs_layout(&self) { + unsafe { + msg_send![self.id(), setNeedsLayout] + } + } + + #[inline] + pub fn needs_layout(&self) -> bool { + unsafe { + let flag: BOOL = msg_send![self.id(), needsLayout]; + flag == YES + } + } + + #[inline] + pub fn layout_if_needed(&self) { + unsafe { + msg_send![self.id(), layoutIfNeeded] + } + } + + #[inline] + pub fn layout_sublayers(&self) { + unsafe { + msg_send![self.id(), layoutSublayers] + } + } + + #[inline] + pub fn resize_sublayers_with_old_size(&self, size: &CGSize) { + unsafe { + msg_send![self.id(), resizeSublayersWithOldSize:*size] + } + } + + #[inline] + pub fn resize_with_old_superlayer_size(&self, size: &CGSize) { + unsafe { + msg_send![self.id(), resizeWithOldSuperlayerSize:*size] + } + } + + // Action methods + + #[inline] + pub fn default_action_for_key(event: &str) -> id { + unsafe { + let event: CFString = CFString::from(event); + msg_send![class!(CALayer), defaultActionForKey:event.as_CFTypeRef()] + } + } + + #[inline] + pub fn action_for_key(&self, event: &str) -> id { + unsafe { + let event: CFString = CFString::from(event); + msg_send![self.id(), actionForKey:event.as_CFTypeRef()] + } + } + + #[inline] + pub fn actions(&self) -> CFDictionary { + unsafe { + msg_send![self.id(), actions] + } + } + + #[inline] + pub unsafe fn set_actions(&self, actions: CFDictionary) { + msg_send![self.id(), setActions:actions] + } + + // TODO(pcwalton): Wrap `CAAnimation`. + #[inline] + pub unsafe fn add_animation_for_key(&self, animation: id, for_key: Option<&str>) { + let for_key: Option = for_key.map(CFString::from); + let for_key: CFTypeRef = match for_key { + Some(ref for_key) => for_key.as_CFTypeRef(), + None => ptr::null(), + }; + msg_send![self.id(), addAnimation:animation forKey:for_key] + } + + #[inline] + pub fn remove_all_animation(&self) { + unsafe { + msg_send![self.id(), removeAllAnimations] + } + } + + #[inline] + pub fn remove_animation_for_key(&self, key: &str) { + unsafe { + let key = CFString::from(key); + msg_send![self.id(), removeAnimationForKey:key.as_CFTypeRef()] + } + } + + #[inline] + pub fn animation_keys(&self) -> Vec { + unsafe { + let keys: CFArrayRef = msg_send![self.id(), animationKeys]; + let keys: CFArray = TCFType::wrap_under_create_rule(keys); + keys.into_iter().map(|string| { + CFString::wrap_under_get_rule(*string as CFStringRef).to_string() + }).collect() + } + } + + #[inline] + pub fn animation_for_key(&self, key: &str) -> id { + unsafe { + let key = CFString::from(key); + msg_send![self.id(), animationForKey:key.as_CFTypeRef()] + } + } + + // Miscellaneous properties + + #[inline] + pub fn name(&self) -> String { + unsafe { + let name: CFStringRef = msg_send![self.id(), name]; + CFString::wrap_under_get_rule(name).to_string() + } + } + + #[inline] + pub fn set_name(&self, name: &str) { + unsafe { + let name = CFString::from(name); + msg_send![self.id(), setName:name.as_CFTypeRef()] + } + } + + #[inline] + pub fn delegate(&self) -> id { + unsafe { + msg_send![self.id(), delegate] + } + } + + #[inline] + pub unsafe fn set_delegate(&self, delegate: id) { + msg_send![self.id(), setDelegate:delegate] + } + + #[inline] + pub fn style(&self) -> Option { + unsafe { + let dictionary: CFDictionaryRef = msg_send![self.id(), style]; + if dictionary.is_null() { + None + } else { + Some(CFDictionary::wrap_under_get_rule(dictionary)) + } + } + } + + #[inline] + pub fn set_style(&self, dictionary: Option) { + unsafe { + let dictionary = match dictionary { + None => ptr::null(), + Some(ref dictionary) => dictionary.as_CFTypeRef(), + }; + msg_send![self.id(), setStyle:dictionary] + } + } + + // Private methods + + #[inline] + pub fn reload_value_for_key_path(&self, key: &str) { + unsafe { + let key = CFString::from(key); + msg_send![self.id(), reloadValueForKeyPath:key.as_CFTypeRef()] + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ContentsGravity { + Center, + Top, + Bottom, + Left, + Right, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Resize, + ResizeAspect, + ResizeAspectFill, + Other(CFString), +} + +impl ContentsGravity { + fn into_CFString(self) -> CFString { + let string = match self { + ContentsGravity::Center => "center", + ContentsGravity::Top => "top", + ContentsGravity::Bottom => "bottom", + ContentsGravity::Left => "left", + ContentsGravity::Right => "right", + ContentsGravity::TopLeft => "topLeft", + ContentsGravity::TopRight => "topRight", + ContentsGravity::BottomLeft => "bottomLeft", + ContentsGravity::BottomRight => "bottomRight", + ContentsGravity::Resize => "resize", + ContentsGravity::ResizeAspect => "resizeAspect", + ContentsGravity::ResizeAspectFill => "resizeAspectFill", + ContentsGravity::Other(other) => return other, + }; + CFString::from(string) + } + + // FIXME(pcwalton): Inefficient. + fn from_CFString(string: CFString) -> ContentsGravity { + match string.to_string() { + ref s if s == "center" => ContentsGravity::Center, + ref s if s == "top" => ContentsGravity::Top, + ref s if s == "bottom" => ContentsGravity::Bottom, + ref s if s == "left" => ContentsGravity::Left, + ref s if s == "right" => ContentsGravity::Right, + ref s if s == "topLeft" => ContentsGravity::TopLeft, + ref s if s == "topRight" => ContentsGravity::TopRight, + ref s if s == "bottomLeft" => ContentsGravity::BottomLeft, + ref s if s == "bottomRight" => ContentsGravity::BottomRight, + ref s if s == "resize" => ContentsGravity::Resize, + ref s if s == "resizeAspect" => ContentsGravity::ResizeAspect, + ref s if s == "resizeAspectFill" => ContentsGravity::ResizeAspectFill, + _ => ContentsGravity::Other(string), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ContentsFormat { + RGBA8Uint, // kCAContentsFormatRGBA8Uint, "RGBA" + RGBA16Float, // kCAContentsFormatRGBA16Float, "RGBAh" + Gray8Uint, // kCAContentsFormatGray8Uint, "Gray8" + Other(CFString), +} + +impl ContentsFormat { + fn into_CFString(self) -> CFString { + let string = match self { + ContentsFormat::RGBA8Uint => "RGBA8", + ContentsFormat::RGBA16Float => "RGBAh", + ContentsFormat::Gray8Uint => "Gray8", + ContentsFormat::Other(other) => return other, + }; + CFString::from(string) + } + + // FIXME(pcwalton): Inefficient. + fn from_CFString(string: CFString) -> ContentsFormat { + match string.to_string() { + ref s if s == "RGBA8" => ContentsFormat::RGBA8Uint, + ref s if s == "RGBAh" => ContentsFormat::RGBA16Float, + ref s if s == "Gray8" => ContentsFormat::Gray8Uint, + _ => ContentsFormat::Other(string), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Filter { + Nearest, + Linear, + Trilinear, + Other(CFString), +} + +impl Filter { + fn into_CFString(self) -> CFString { + let string = match self { + Filter::Nearest => "nearest", + Filter::Linear => "linear", + Filter::Trilinear => "trilinear", + Filter::Other(other) => return other, + }; + CFString::from(string) + } + + // FIXME(pcwalton): Inefficient. + fn from_CFString(string: CFString) -> Filter { + match string.to_string() { + ref s if s == "nearest" => Filter::Nearest, + ref s if s == "linear" => Filter::Linear, + ref s if s == "trilinear" => Filter::Trilinear, + _ => Filter::Other(string), + } + } +} + +bitflags! { + pub struct EdgeAntialiasingMask: u32 { + const LEFT_EDGE = 1 << 0; // kCALayerLeftEdge + const RIGHT_EDGE = 1 << 1; // kCALayerRightEdge + const BOTTOM_EDGE = 1 << 2; // kCALayerBottomEdge + const TOP_EDGE = 1 << 3; // kCALayerTopEdge + } +} + +bitflags! { + pub struct CornerMask: NSUInteger { + const MIN_X_MIN_Y_CORNER = 1 << 0; // kCALayerMinXMinYCorner + const MAX_X_MIN_Y_CORNER = 1 << 1; // kCALayerMaxXMinYCorner + const MIN_X_MAX_Y_CORNER = 1 << 2; // kCALayerMinXMaxYCorner + const MAX_X_MAX_Y_CORNER = 1 << 3; // kCALayerMaxXMaxYCorner + } +} + +bitflags! { + pub struct AutoresizingMask: u32 { + const NOT_SIZABLE = 0; // kCALayerNotSizable + const MIN_X_MARGIN = 1 << 0; // kCALayerMinXMargin + const WIDTH_SIZABLE = 1 << 1; // kCALayerWidthSizable + const MAX_X_MARGIN = 1 << 2; // kCALayerMaxXMargin + const MIN_Y_MARGIN = 1 << 3; // kCALayerMinYMargin + const HEIGHT_SIZABLE = 1 << 4; // kCALayerHeightSizable + const MAX_Y_MARGIN = 1 << 5; // kCALayerMaxYMargin + } +} + +// CATransaction.h + +// You can't actually construct any `CATransaction` objects, so that class is +// really just a module. +pub mod transaction { + use core_foundation::date::CFTimeInterval; + use core_foundation::string::CFString; + + use base::{BOOL, YES, id}; + + #[inline] + pub fn begin() { + unsafe { + msg_send![class!(CATransaction), begin] + } + } + + #[inline] + pub fn commit() { + unsafe { + msg_send![class!(CATransaction), commit] + } + } + + #[inline] + pub fn flush() { + unsafe { + msg_send![class!(CATransaction), flush] + } + } + + #[inline] + pub fn lock() { + unsafe { + msg_send![class!(CATransaction), lock] + } + } + + #[inline] + pub fn unlock() { + unsafe { + msg_send![class!(CATransaction), unlock] + } + } + + #[inline] + pub fn animation_duration() -> CFTimeInterval { + unsafe { + msg_send![class!(CATransaction), animationDuration] + } + } + + #[inline] + pub fn set_animation_duration(duration: CFTimeInterval) { + unsafe { + msg_send![class!(CATransaction), setAnimationDuration:duration] + } + } + + #[inline] + pub fn animation_timing_function() -> id { + unsafe { + msg_send![class!(CATransaction), animationTimingFunction] + } + } + + #[inline] + pub unsafe fn set_animation_timing_function(function: id) { + msg_send![class!(CATransaction), setAnimationTimingFunction:function] + } + + #[inline] + pub fn disable_actions() -> bool { + unsafe { + let flag: BOOL = msg_send![class!(CATransaction), disableActions]; + flag == YES + } + } + + #[inline] + pub fn set_disable_actions(flag: bool) { + unsafe { + msg_send![class!(CATransaction), setDisableActions:flag as BOOL] + } + } + + // Omitted: `completionBlock`; depends on blocks. + // Omitted: `setCompletionBlock:`; depends on blocks. + + #[inline] + pub fn value_for_key(key: &str) -> id { + unsafe { + let key: CFString = CFString::from(key); + msg_send![class!(CATransaction), valueForKey:key] + } + } + + #[inline] + pub fn set_value_for_key(value: id, key: &str) { + unsafe { + let key: CFString = CFString::from(key); + msg_send![class!(CATransaction), setValue:value forKey:key] + } + } +} + +// CATransform3D.h + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CATransform3D { + pub m11: CGFloat, pub m12: CGFloat, pub m13: CGFloat, pub m14: CGFloat, + pub m21: CGFloat, pub m22: CGFloat, pub m23: CGFloat, pub m24: CGFloat, + pub m31: CGFloat, pub m32: CGFloat, pub m33: CGFloat, pub m34: CGFloat, + pub m41: CGFloat, pub m42: CGFloat, pub m43: CGFloat, pub m44: CGFloat, +} + +impl PartialEq for CATransform3D { + #[inline] + fn eq(&self, other: &CATransform3D) -> bool { + unsafe { + CATransform3DEqualToTransform(*self, *other) + } + } +} + +impl Mul for CATransform3D { + type Output = CATransform3D; + + #[inline] + fn mul(self, other: CATransform3D) -> CATransform3D { + unsafe { + CATransform3DConcat(self, other) + } + } +} + +impl CATransform3D { + pub const IDENTITY: CATransform3D = CATransform3D { + m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0, + m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0, + m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, + m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0, + }; + + #[inline] + pub fn from_translation(tx: CGFloat, ty: CGFloat, tz: CGFloat) -> CATransform3D { + unsafe { + CATransform3DMakeTranslation(tx, ty, tz) + } + } + + #[inline] + pub fn from_scale(sx: CGFloat, sy: CGFloat, sz: CGFloat) -> CATransform3D { + unsafe { + CATransform3DMakeScale(sx, sy, sz) + } + } + + #[inline] + pub fn from_rotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D { + unsafe { + CATransform3DMakeRotation(angle, x, y, z) + } + } + + #[inline] + pub fn affine(affine_transform: CGAffineTransform) -> CATransform3D { + unsafe { + CATransform3DMakeAffineTransform(affine_transform) + } + } + + #[inline] + pub fn is_identity(&self) -> bool { + unsafe { + CATransform3DIsIdentity(*self) + } + } + + #[inline] + pub fn translate(&self, tx: CGFloat, ty: CGFloat, tz: CGFloat) -> CATransform3D { + unsafe { + CATransform3DTranslate(*self, tx, ty, tz) + } + } + + #[inline] + pub fn scale(&self, sx: CGFloat, sy: CGFloat, sz: CGFloat) -> CATransform3D { + unsafe { + CATransform3DScale(*self, sx, sy, sz) + } + } + + #[inline] + pub fn rotate(&self, angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat) -> CATransform3D { + unsafe { + CATransform3DRotate(*self, angle, x, y, z) + } + } + + #[inline] + pub fn invert(&self) -> CATransform3D { + unsafe { + CATransform3DInvert(*self) + } + } + + #[inline] + pub fn is_affine(&self) -> bool { + unsafe { + CATransform3DIsAffine(*self) + } + } + + #[inline] + pub fn to_affine(&self) -> CGAffineTransform { + unsafe { + CATransform3DGetAffineTransform(*self) + } + } +} + +#[link(name = "QuartzCore", kind = "framework")] +extern { + fn CATransform3DIsIdentity(t: CATransform3D) -> bool; + fn CATransform3DEqualToTransform(a: CATransform3D, b: CATransform3D) -> bool; + fn CATransform3DMakeTranslation(tx: CGFloat, ty: CGFloat, tz: CGFloat) -> CATransform3D; + fn CATransform3DMakeScale(sx: CGFloat, sy: CGFloat, sz: CGFloat) -> CATransform3D; + fn CATransform3DMakeRotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat) + -> CATransform3D; + fn CATransform3DTranslate(t: CATransform3D, tx: CGFloat, ty: CGFloat, tz: CGFloat) + -> CATransform3D; + fn CATransform3DScale(t: CATransform3D, sx: CGFloat, sy: CGFloat, sz: CGFloat) + -> CATransform3D; + fn CATransform3DRotate(t: CATransform3D, angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat) + -> CATransform3D; + fn CATransform3DConcat(a: CATransform3D, b: CATransform3D) -> CATransform3D; + fn CATransform3DInvert(t: CATransform3D) -> CATransform3D; + fn CATransform3DMakeAffineTransform(m: CGAffineTransform) -> CATransform3D; + fn CATransform3DIsAffine(t: CATransform3D) -> bool; + fn CATransform3DGetAffineTransform(t: CATransform3D) -> CGAffineTransform; +} diff --git a/core-graphics/src/color.rs b/core-graphics/src/color.rs index f8364f1..79ef9a0 100644 --- a/core-graphics/src/color.rs +++ b/core-graphics/src/color.rs @@ -12,6 +12,8 @@ use base::CGFloat; use core_foundation::base::TCFType; use super::sys::{CGColorRef}; +pub use super::sys::CGColorRef as SysCGColorRef; + declare_TCFType!{ CGColor, CGColorRef }