//! A wrapper for `NSLayoutConstraint` that's more general in nature. You can think of this as an //! escape hatch, if you need it (we use it for things like width and height, which aren't handled //! by an axis). use core_graphics::base::CGFloat; use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::ShareId; use crate::foundation::id; /// A wrapper for `NSLayoutConstraint`. This both acts as a central path through which to activate /// constraints, as well as a wrapper for layout constraints that are not axis bound (e.g, width or /// height). #[derive(Clone, Debug)] pub struct LayoutConstraint { /// A shared pointer to the underlying view. Provided your view isn't dropped, this will always /// be valid. pub constraint: ShareId, /// The offset used in computing this constraint. pub offset: f64, /// The multiplier used in computing this constraint. pub multiplier: f64, /// The priority used in computing this constraint. pub priority: f64, } impl LayoutConstraint { /// An internal method for wrapping existing constraints. pub(crate) fn new(object: id) -> Self { LayoutConstraint { constraint: unsafe { ShareId::from_ptr(object) }, offset: 0.0, multiplier: 0.0, priority: 0.0 } } /// Sets the offset for this constraint. pub fn offset>(self, offset: F) -> Self { let offset: f64 = offset.into(); unsafe { let o = offset as CGFloat; let _: () = msg_send![&*self.constraint, setConstant:o]; } LayoutConstraint { constraint: self.constraint, offset: offset, multiplier: self.multiplier, priority: self.priority } } /// Call this with your batch of constraints to activate them. // If you're astute, you'll note that, yes... this is kind of hacking around some // borrowing rules with how objc_id::Id/objc_id::ShareId works. In this case, to // support the way autolayout constraints work over in the cocoa runtime, we need to be // able to clone these and pass them around... while also getting certain references to // them. // // I regret nothing, lol. If you have a better solution I'm all ears. pub fn activate(constraints: &[LayoutConstraint]) { unsafe { let ids: Vec<&Object> = constraints.into_iter().map(|constraint| { &*constraint.constraint }).collect(); let constraints: id = msg_send![class!(NSArray), arrayWithObjects:ids.as_ptr() count:ids.len()]; let _: () = msg_send![class!(NSLayoutConstraint), activateConstraints:constraints]; } } }