From 9446092169464dc323335b3aba8f5af72e3e85ff Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Tue, 16 Mar 2021 18:21:31 -0700 Subject: [PATCH] Clean up AutoLayout wrapper. - Anchors are now enums, which help in debugging constraint issues. - Enum types that are acceptable for constraint generation are now matched at runtime, and provide better error messages if a constraint can't be satisfied and crashes the app. - `left` and `right` anchors are now supported on all widgets, fixing an oversight from early iterations of the framework. - Reduces `unsafe` usage by a decent amount when setting constraint pointers for widget types. --- src/button/mod.rs | 24 +++-- src/image/mod.rs | 26 ++++-- src/input/mod.rs | 46 +++++---- src/layout/dimension.rs | 161 ++++++++++++++++++++------------ src/layout/horizontal.rs | 197 ++++++++++++++++++++++++++++++++------- src/layout/traits.rs | 41 +++++++- src/layout/vertical.rs | 118 ++++++++++++++++------- src/listview/mod.rs | 51 ++++++---- src/listview/row/mod.rs | 66 ++++++++----- src/progress/mod.rs | 42 +++++---- src/scrollview/mod.rs | 46 +++++---- src/switch.rs | 25 +++-- src/text/label/mod.rs | 46 +++++---- src/view/mod.rs | 44 +++++---- 14 files changed, 650 insertions(+), 283 deletions(-) diff --git a/src/button/mod.rs b/src/button/mod.rs index 7ec6fcc..5975946 100644 --- a/src/button/mod.rs +++ b/src/button/mod.rs @@ -38,9 +38,15 @@ pub struct Button { /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -77,14 +83,16 @@ impl Button { Button { handler: None, image: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } diff --git a/src/image/mod.rs b/src/image/mod.rs index 612cca5..d8cf22e 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -44,16 +44,22 @@ fn allocate_view(registration_fn: fn() -> *const Class) -> id { pub struct ImageView { /// A pointer to the Objective-C runtime view controller. pub objc: ShareId, - + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -82,14 +88,16 @@ impl ImageView { let view = allocate_view(register_image_view_class); ImageView { - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } diff --git a/src/input/mod.rs b/src/input/mod.rs index 284da77..40b2d77 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -89,16 +89,22 @@ pub struct TextField { /// A pointer to the delegate for this view. pub delegate: Option>, - + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -128,14 +134,16 @@ impl TextField { TextField { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } @@ -157,14 +165,16 @@ impl TextField where T: TextFieldDelegate + 'static { let mut label = TextField { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![label, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![label, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![label, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![label, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![label, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![label, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![label, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![label, centerYAnchor] }), + top: LayoutAnchorY::top(label), + left: LayoutAnchorX::left(label), + leading: LayoutAnchorX::leading(label), + right: LayoutAnchorX::right(label), + trailing: LayoutAnchorX::trailing(label), + bottom: LayoutAnchorY::bottom(label), + width: LayoutAnchorDimension::width(label), + height: LayoutAnchorDimension::height(label), + center_x: LayoutAnchorX::center(label), + center_y: LayoutAnchorY::center(label), objc: unsafe { ShareId::from_ptr(label) }, }; @@ -184,7 +194,9 @@ impl TextField { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), diff --git a/src/layout/dimension.rs b/src/layout/dimension.rs index e23f6d4..cce0a3a 100644 --- a/src/layout/dimension.rs +++ b/src/layout/dimension.rs @@ -1,6 +1,3 @@ -//! A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height` -//! values for how a given view should layout. - use core_graphics::base::CGFloat; use objc::{class, msg_send, sel, sel_impl}; @@ -15,82 +12,128 @@ use super::attributes::{LayoutAttribute, LayoutRelation}; /// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a /// factory/helper for creating `LayoutConstraint` objects based on your views. #[derive(Clone, Debug, Default)] -pub struct LayoutAnchorDimension(pub Option>); +pub struct LayoutAnchorDimension2(pub Option>); + +/// A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height` +/// values for how a given view should layout. +#[derive(Clone, Debug)] +pub enum LayoutAnchorDimension { + /// Represents an uninitialized anchor (e.g, for a view that's not created yet). + Uninitialized, + + /// Represents a Width anchor. + Width(ShareId), + + /// Represents a Height anchor. + Height(ShareId) +} + +impl Default for LayoutAnchorDimension { + /// Returns an Uninitialized anchor dimension by default. + fn default() -> Self { + Self::Uninitialized + } +} impl LayoutAnchorDimension { - /// An internal method for wrapping existing anchors. - pub(crate) fn new(object: id) -> Self { - LayoutAnchorDimension(Some(unsafe { - ShareId::from_ptr(object) - })) + /// Given a view, returns an anchor for the width anchor. + pub(crate) fn width(view: id) -> Self { + Self::Width(unsafe { + ShareId::from_ptr(msg_send![view, widthAnchor]) + }) + } + + /// Given a view, returns an anchor for the height anchor. + pub(crate) fn height(view: id) -> Self { + Self::Height(unsafe { + ShareId::from_ptr(msg_send![view, heightAnchor]) + }) } /// Return a constraint equal to a constant value. pub fn constraint_equal_to_constant(&self, constant: f64) -> LayoutConstraint { - match &self.0 { - Some(from) => LayoutConstraint::new(unsafe { + if let Self::Width(obj) | Self::Height(obj) = self { + return LayoutConstraint::new(unsafe { let value = constant as CGFloat; - msg_send![*from, constraintEqualToConstant:value] - }), + msg_send![*obj, constraintEqualToConstant:value] + }); + } + + panic!("Attempted to create a constant constraint with an uninitialized anchor."); + } - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } + /// Return a constraint greater than or equal to a constant value. + pub fn constraint_greater_than_or_equal_to_constant(&self, constant: f64) -> LayoutConstraint { + if let Self::Width(obj) | Self::Height(obj) = self { + return LayoutConstraint::new(unsafe { + let value = constant as CGFloat; + msg_send![*obj, constraintGreaterThanOrEqualToConstant:value] + }); + } + + panic!("Attempted to create a constraint (>=) with an uninitialized anchor."); + } + + /// Return a constraint greater than or equal to a constant value. + pub fn constraint_less_than_or_equal_to_constant(&self, constant: f64) -> LayoutConstraint { + if let Self::Width(obj) | Self::Height(obj) = self { + return LayoutConstraint::new(unsafe { + let value = constant as CGFloat; + msg_send![*obj, constraintLessThanOrEqualToConstant:value] + }); + } + + panic!("Attempted to create a constraint (<=) with an uninitialized anchor."); + } + + /// Boilerplate for handling constraint construction and panic'ing with some more helpful + /// messages. The goal here is to make AutoLayout slightly easier to debug when things go + /// wrong. + fn constraint_with(&self, anchor_to: &LayoutAnchorDimension, handler: F) -> LayoutConstraint + where + F: Fn(&ShareId, &ShareId) -> id + { + match (self, anchor_to) { + (Self::Width(from), Self::Width(to)) | + (Self::Width(from), Self::Height(to)) | + (Self::Height(from), Self::Width(to)) | + (Self::Height(from), Self::Height(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Uninitialized, Self::Uninitialized) => { + panic!("Attempted to create constraints with an uninitialized \"from\" and \"to\" dimension anchor."); + }, + + (Self::Uninitialized, _) => { + panic!("Attempted to create constraints with an uninitialized \"from\" dimension anchor."); + }, + + + (_, Self::Uninitialized) => { + panic!("Attempted to create constraints with an uninitialized \"to\" dimension anchor."); + } } } /// Return a constraint equal to another dimension anchor. pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintEqualToAnchor:&**to] + }) } /// Return a constraint greater than or equal to another dimension anchor. pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } - } - } - - /// Return a constraint greater than or equal to a constant value. - pub fn constraint_greater_than_or_equal_to_constant(&self, constant: f64) -> LayoutConstraint { - match &self.0 { - Some(from) => LayoutConstraint::new(unsafe { - let value = constant as CGFloat; - msg_send![*from, constraintGreaterThanOrEqualToConstant:value] - }), - - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] + }) } /// Return a constraint less than or equal to another dimension anchor. pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } - } - } - - /// Return a constraint greater than or equal to a constant value. - pub fn constraint_less_than_or_equal_to_constant(&self, constant: f64) -> LayoutConstraint { - match &self.0 { - Some(from) => LayoutConstraint::new(unsafe { - let value = constant as CGFloat; - msg_send![*from, constraintLessThanOrEqualToConstant:value] - }), - - _ => { panic!("Attempted to create constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] + }) } } diff --git a/src/layout/horizontal.rs b/src/layout/horizontal.rs index 5e343db..e3ef892 100644 --- a/src/layout/horizontal.rs +++ b/src/layout/horizontal.rs @@ -1,7 +1,3 @@ -//! A wrapper for `NSLayoutAnchorX`, which is typically used to handle values for how a -//! given view should layout along the x-axis. Of note: the only thing that can't be protected -//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful! - use objc::{msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::ShareId; @@ -9,49 +5,182 @@ use objc_id::ShareId; use crate::foundation::id; use crate::layout::constraint::LayoutConstraint; -/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a -/// factory/helper for creating `LayoutConstraint` objects based on your views. -#[derive(Clone, Debug, Default)] -pub struct LayoutAnchorX(pub Option>); +/// A wrapper for `NSLayoutAnchorX`, used to handle values for how a given view should +/// layout along the x-axis. +/// +/// Of note: mismatches of incorrect left/leading and right/trailing anchors are detected at +/// runtime, and will panic - this is by design, as your UI needs to work. Be careful! +#[derive(Clone, Debug)] +pub enum LayoutAnchorX { + /// Represents an uninitialized anchor (e.g, for a view that's not created yet). + Uninitialized, + + /// Represents a leading anchor; side depends on system orientation. + Leading(ShareId), + + /// Represents a left anchor. + Left(ShareId), + + /// Represents a trailing anchor; side depends on system orientation. + Trailing(ShareId), + + /// Represents a right anchor. + Right(ShareId), + + /// Represents a center anchor on the X axis. + Center(ShareId) +} + +impl Default for LayoutAnchorX { + /// Returns an uninitialized anchor by default. + fn default() -> Self { + Self::Uninitialized + } +} impl LayoutAnchorX { - /// An internal method for wrapping existing anchors. - pub(crate) fn new(object: id) -> Self { - LayoutAnchorX(Some(unsafe { - ShareId::from_ptr(object) - })) + /// Given a view, returns an anchor for the leading anchor. + pub(crate) fn leading(view: id) -> Self { + Self::Leading(unsafe { + ShareId::from_ptr(msg_send![view, leadingAnchor]) + }) + } + + /// Given a view, returns an anchor for the left anchor. + pub(crate) fn left(view: id) -> Self { + Self::Left(unsafe { + ShareId::from_ptr(msg_send![view, leftAnchor]) + }) + } + + /// Given a view, returns an anchor for the trailing anchor. + pub(crate) fn trailing(view: id) -> Self { + Self::Trailing(unsafe { + ShareId::from_ptr(msg_send![view, trailingAnchor]) + }) + } + + /// Given a view, returns an anchor for the right anchor. + pub(crate) fn right(view: id) -> Self { + Self::Right(unsafe { + ShareId::from_ptr(msg_send![view, rightAnchor]) + }) + } + + /// Given a view, returns an anchor for the right anchor. + pub(crate) fn center(view: id) -> Self { + Self::Center(unsafe { + ShareId::from_ptr(msg_send![view, centerXAnchor]) + }) + } + + /// Boilerplate for handling constraint construction and panic'ing with some more helpful + /// messages. The goal here is to make AutoLayout slightly easier to debug when things go + /// wrong. + fn constraint_with(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint + where + F: Fn(&ShareId, &ShareId) -> id + { + match (self, anchor_to) { + // The anchors that can connect to each other. These blocks could be condensed, but are + // kept separate for readability reasons. + (Self::Leading(from), Self::Leading(to)) | (Self::Leading(from), Self::Trailing(to)) | + (Self::Leading(from), Self::Center(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Trailing(from), Self::Trailing(to)) | (Self::Trailing(from), Self::Leading(to)) | + (Self::Trailing(from), Self::Center(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Left(from), Self::Left(to)) | (Self::Left(from), Self::Right(to)) | + (Self::Left(from), Self::Center(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Right(from), Self::Right(to)) | (Self::Right(from), Self::Left(to)) | + (Self::Right(from), Self::Center(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Center(from), Self::Center(to)) | (Self::Center(from), Self::Leading(to)) | + (Self::Center(from), Self::Trailing(to)) | (Self::Center(from), Self::Left(to)) | + (Self::Center(from), Self::Right(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + // These anchors explicitly cannot be attached to each other, as it results in + // undefined/unexpected layout behavior when a system has differing ltr/rtl setups. + (Self::Leading(_), Self::Left(_)) | (Self::Left(_), Self::Leading(_)) => { + panic!(r#" + Attempted to attach a "leading" constraint to a "left" constraint. This will + result in undefined behavior for LTR and RTL system settings, and Cacao blocks this. + + Use either left/right or leading/trailing. + "#); + }, + + (Self::Leading(_), Self::Right(_)) | (Self::Right(_), Self::Leading(_)) => { + panic!(r#" + Attempted to attach a "leading" constraint to a "right" constraint. This will + result in undefined behavior for LTR and RTL system settings, and Cacao blocks this. + + Use either left/right or leading/trailing. + "#); + }, + + (Self::Trailing(_), Self::Left(_)) | (Self::Left(_), Self::Trailing(_)) => { + panic!(r#" + Attempted to attach a "trailing" constraint to a "left" constraint. This will + result in undefined behavior for LTR and RTL system settings, and Cacao blocks this. + + Use either left/right or leading/trailing. + "#); + }, + + (Self::Trailing(_), Self::Right(_)) | (Self::Right(_), Self::Trailing(_)) => { + panic!(r#" + Attempted to attach a "trailing" constraint to a "right" constraint. This will + result in undefined behavior for LTR and RTL system settings, and Cacao blocks this. + + Use either left/right or leading/trailing. + "#); + }, + + // If anything is attempted with an uninitialized anchor, then block it. + (Self::Uninitialized, Self::Uninitialized) => { + panic!("Attempted to create constraints with an uninitialized \"from\" and \"to\" X anchor."); + }, + + (Self::Uninitialized, _) => { + panic!("Attempted to create constraints with an uninitialized \"from\" X anchor."); + }, + + (_, Self::Uninitialized) => { + panic!("Attempted to create constraints with an uninitialized \"to\" X anchor."); + } + } } /// Return a constraint equal to another horizontal anchor. pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintEqualToAnchor:&**to] + }) } /// Return a constraint greater than or equal to another horizontal anchor. pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] + }) } /// Return a constraint less than or equal to another horizontal anchor. pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] + }) } } diff --git a/src/layout/traits.rs b/src/layout/traits.rs index 4a4faba..e439498 100644 --- a/src/layout/traits.rs +++ b/src/layout/traits.rs @@ -1,16 +1,53 @@ //! Various traits related to controllers opting in to autolayout routines and support for view //! heirarchies. +use core_graphics::geometry::{CGRect, CGPoint, CGSize}; + +use objc::{msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::ShareId; +use crate::foundation::{id, YES, NO}; +use crate::geometry::Rect; + /// A trait that view wrappers must conform to. Enables managing the subview tree. +#[allow(unused_variables)] pub trait Layout { /// Returns a reference to the backing Objective-C layer. This is optional, as we try to keep /// the general lazy-loading approach Cocoa has. This may change in the future, and in general /// this shouldn't affect your code too much (if at all). fn get_backing_node(&self) -> ShareId; - /// This trait should implement adding a view to the subview tree for a given view. - fn add_subview(&self, _view: &V); + /// This trait method should implement adding a view to the subview tree for a given view. + fn add_subview(&self, view: &V); + + /// Sets the `frame` for the view this trait is applied to. + /// + /// Note that Cacao, by default, opts into autolayout - you need to call + /// `set_translates_autoresizing_mask_into_constraints` to enable frame-based layout calls (or + /// use an appropriate initializer for a given view type). + fn set_frame>(&self, rect: R) { + let backing_node = self.get_backing_node(); + let frame: CGRect = rect.into(); + + unsafe { + let _: () = msg_send![&*backing_node, setFrame:frame]; + } + } + + /// Sets whether the view for this trait should translate autoresizing masks into layout + /// constraints. + /// + /// Cacao defaults this to `false`; if you need to set frame-based layout pieces, + /// then you should set this to `true` (or use an appropriate initializer that does it for you). + fn set_translates_autoresizing_mask_into_constraints(&self, translates: bool) { + let backing_node = self.get_backing_node(); + + unsafe { + let _: () = msg_send![&*backing_node, setTranslatesAutoresizingMaskIntoConstraints:match translates { + true => YES, + false => NO + }]; + } + } } diff --git a/src/layout/vertical.rs b/src/layout/vertical.rs index b009120..d9a7895 100644 --- a/src/layout/vertical.rs +++ b/src/layout/vertical.rs @@ -1,7 +1,3 @@ -//! A wrapper for `NSLayoutAnchorX`, which is typically used to handle values for how a -//! given view should layout along the x-axis. Of note: the only thing that can't be protected -//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful! - use objc::{msg_send, sel, sel_impl}; use objc::runtime::Object; use objc_id::ShareId; @@ -9,50 +5,102 @@ use objc_id::ShareId; use crate::foundation::id; use crate::layout::constraint::LayoutConstraint; -/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a -/// factory/helper for creating `LayoutConstraint` objects based on your views. -#[derive(Clone, Debug, Default)] -pub struct LayoutAnchorY(pub Option>); +/// A wrapper for `NSLayoutAnchorY`, used to handle values for how a given view should +/// layout along the y-axis. +#[derive(Clone, Debug)] +pub enum LayoutAnchorY { + /// Represents an uninitialized anchor (e.g, for a view that's not created yet). + Uninitialized, + + /// Represents a top anchor. + Top(ShareId), + + /// Represents a bottom anchor. + Bottom(ShareId), + + /// Represents a center anchor for the Y axis. + Center(ShareId) +} + +impl Default for LayoutAnchorY { + fn default() -> Self { + Self::Uninitialized + } +} impl LayoutAnchorY { - /// An internal method for wrapping existing constraints. - pub(crate) fn new(object: id) -> Self { - LayoutAnchorY(Some(unsafe { - ShareId::from_ptr(object) - })) + /// Given a view, returns an anchor for the top anchor. + pub(crate) fn top(view: id) -> Self { + Self::Top(unsafe { + ShareId::from_ptr(msg_send![view, topAnchor]) + }) + } + + /// Given a view, returns an anchor for the bottom anchor. + pub(crate) fn bottom(view: id) -> Self { + Self::Bottom(unsafe { + ShareId::from_ptr(msg_send![view, bottomAnchor]) + }) + } + + /// Given a view, returns an anchor for the center Y anchor. + pub(crate) fn center(view: id) -> Self { + Self::Center(unsafe { + ShareId::from_ptr(msg_send![view, centerYAnchor]) + }) + } + + /// Boilerplate for handling constraint construction and panic'ing with some more helpful + /// messages. The goal here is to make AutoLayout slightly easier to debug when things go + /// wrong. + fn constraint_with(&self, anchor_to: &LayoutAnchorY, handler: F) -> LayoutConstraint + where + F: Fn(&ShareId, &ShareId) -> id + { + match (self, anchor_to) { + (Self::Top(from), Self::Top(to)) | (Self::Top(from), Self::Bottom(to)) | + (Self::Top(from), Self::Center(to)) | + + (Self::Bottom(from), Self::Bottom(to)) | (Self::Bottom(from), Self::Top(to)) | + (Self::Bottom(from), Self::Center(to)) | + + (Self::Center(from), Self::Center(to)) | (Self::Center(from), Self::Top(to)) | + (Self::Center(from), Self::Bottom(to)) => { + LayoutConstraint::new(handler(from, to)) + }, + + (Self::Uninitialized, Self::Uninitialized) => { + panic!("Attempted to create constraints with uninitialized \"from\" and \"to\" y anchors."); + }, + + (Self::Uninitialized, _) => { + panic!("Attempted to create constraints with an uninitialized \"from\" y anchor."); + }, + + (_, Self::Uninitialized) => { + panic!("Attempted to create constraints with an uninitialized \"to\" y anchor."); + } + } } /// Return a constraint equal to another vertical anchor. pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - let b: id = msg_send![*from, constraintEqualToAnchor:&**to]; - b - }), - - _ => { panic!("Attempted to create vertical constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintEqualToAnchor:&**to] + }) } /// Return a constraint greater than or equal to another vertical anchor. pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create vertical constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] + }) } /// Return a constraint less than or equal to another vertical anchor. pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { - match (&self.0, &anchor_to.0) { - (Some(from), Some(to)) => LayoutConstraint::new(unsafe { - msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] - }), - - _ => { panic!("Attempted to create vertical constraints with an uninitialized anchor!"); } - } + self.constraint_with(anchor_to, |from, to| unsafe { + msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] + }) } } diff --git a/src/listview/mod.rs b/src/listview/mod.rs index 46a55b9..29f5683 100644 --- a/src/listview/mod.rs +++ b/src/listview/mod.rs @@ -200,9 +200,15 @@ pub struct ListView { /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -243,24 +249,27 @@ impl ListView { }; // For macOS, we need to use the NSScrollView anchor points, not the NSTableView. + // @TODO: Fix this with proper mutable access. #[cfg(target_os = "macos")] - let anchor_view = &*scrollview.objc; + let anchor_view: id = unsafe { msg_send![&*scrollview.objc, self] }; #[cfg(target_os = "ios")] - let anchor_view = view; + let anchor_view: id = view; ListView { cell_factory: CellFactory::new(), menu: PropertyNullable::default(), delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![anchor_view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![anchor_view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![anchor_view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![anchor_view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![anchor_view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![anchor_view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![anchor_view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![anchor_view, centerYAnchor] }), + top: LayoutAnchorY::top(anchor_view), + left: LayoutAnchorX::left(anchor_view), + leading: LayoutAnchorX::leading(anchor_view), + right: LayoutAnchorX::right(anchor_view), + trailing: LayoutAnchorX::trailing(anchor_view), + bottom: LayoutAnchorY::bottom(anchor_view), + width: LayoutAnchorDimension::width(anchor_view), + height: LayoutAnchorDimension::height(anchor_view), + center_x: LayoutAnchorX::center(anchor_view), + center_y: LayoutAnchorY::center(anchor_view), objc: unsafe { ShareId::from_ptr(view) }, #[cfg(target_os = "macos")] @@ -300,7 +309,7 @@ impl ListView where T: ListViewDelegate + 'static { // For macOS, we need to use the NSScrollView anchor points, not the NSTableView. #[cfg(target_os = "macos")] - let anchor_view = &*scrollview.objc; + let anchor_view: id = unsafe { msg_send![&*scrollview.objc, self] }; #[cfg(target_os = "ios")] let anchor_view = view; @@ -309,14 +318,16 @@ impl ListView where T: ListViewDelegate + 'static { cell_factory: cell, menu: PropertyNullable::default(), delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![anchor_view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![anchor_view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![anchor_view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![anchor_view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![anchor_view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![anchor_view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![anchor_view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![anchor_view, centerYAnchor] }), + top: LayoutAnchorY::top(anchor_view), + left: LayoutAnchorX::left(anchor_view), + leading: LayoutAnchorX::leading(anchor_view), + right: LayoutAnchorX::right(anchor_view), + trailing: LayoutAnchorX::trailing(anchor_view), + bottom: LayoutAnchorY::bottom(anchor_view), + width: LayoutAnchorDimension::width(anchor_view), + height: LayoutAnchorDimension::height(anchor_view), + center_x: LayoutAnchorX::center(anchor_view), + center_y: LayoutAnchorY::center(anchor_view), objc: unsafe { ShareId::from_ptr(view) }, #[cfg(target_os = "macos")] @@ -341,7 +352,9 @@ impl ListView { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), diff --git a/src/listview/row/mod.rs b/src/listview/row/mod.rs index 87bea96..f916a70 100644 --- a/src/listview/row/mod.rs +++ b/src/listview/row/mod.rs @@ -92,16 +92,22 @@ pub struct ListViewRow { /// A pointer to the delegate for this view. pub delegate: Option>, - + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -131,14 +137,16 @@ impl ListViewRow { ListViewRow { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: Rc::new(RefCell::new(unsafe { Id::from_ptr(view) })), } } @@ -166,14 +174,16 @@ impl ListViewRow where T: ViewDelegate + 'static { let view = ListViewRow { delegate: Some(delegate), - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: Rc::new(RefCell::new(unsafe { Id::from_ptr(view) })), }; @@ -198,14 +208,16 @@ impl ListViewRow where T: ViewDelegate + 'static { let mut view = ListViewRow { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: Rc::new(RefCell::new(unsafe { Id::from_ptr(view) })), }; @@ -226,7 +238,9 @@ impl ListViewRow where T: ViewDelegate + 'static { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), @@ -253,7 +267,9 @@ impl ListViewRow { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), diff --git a/src/progress/mod.rs b/src/progress/mod.rs index 06def78..779a049 100644 --- a/src/progress/mod.rs +++ b/src/progress/mod.rs @@ -35,29 +35,35 @@ pub use enums::ProgressIndicatorStyle; pub struct ProgressIndicator { /// A pointer to the Objective-C Object. pub objc: ShareId, - - /// A pointer to the Objective-C top layout constraint. + + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, - /// A pointer to the Objective-C leading layout constraint. + /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, - /// A pointer to the Objective-C trailing layout constraint. + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, - /// A pointer to the Objective-C bottom layout constraint. + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, - /// A pointer to the Objective-C width layout constraint. + /// A pointer to the Objective-C runtime width layout constraint. pub width: LayoutAnchorDimension, - /// A pointer to the Objective-C height layout constraint. + /// A pointer to the Objective-C runtime height layout constraint. pub height: LayoutAnchorDimension, - /// A pointer to the Objective-C center X layout constraint. + /// A pointer to the Objective-C runtime center X layout constraint. pub center_x: LayoutAnchorX, - /// A pointer to the Objective-C center Y layout constraint. + /// A pointer to the Objective-C runtime center Y layout constraint. pub center_y: LayoutAnchorY } @@ -83,14 +89,16 @@ impl ProgressIndicator { }; ProgressIndicator { - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } diff --git a/src/scrollview/mod.rs b/src/scrollview/mod.rs index 9c09634..3e51d9e 100644 --- a/src/scrollview/mod.rs +++ b/src/scrollview/mod.rs @@ -94,16 +94,22 @@ pub struct ScrollView { /// A pointer to the delegate for this view. pub delegate: Option>, - + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -133,14 +139,16 @@ impl ScrollView { ScrollView { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } @@ -160,14 +168,16 @@ impl ScrollView where T: ScrollViewDelegate + 'static { let mut view = ScrollView { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, }; @@ -187,7 +197,9 @@ impl ScrollView { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), diff --git a/src/switch.rs b/src/switch.rs index 8f8990c..cb60b09 100644 --- a/src/switch.rs +++ b/src/switch.rs @@ -28,9 +28,15 @@ pub struct Switch { /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -45,6 +51,7 @@ pub struct Switch { /// A pointer to the Objective-C runtime center Y layout constraint. pub center_y: LayoutAnchorY + } impl Switch { @@ -62,14 +69,16 @@ impl Switch { Switch { handler: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } diff --git a/src/text/label/mod.rs b/src/text/label/mod.rs index e745ef6..2ecffde 100644 --- a/src/text/label/mod.rs +++ b/src/text/label/mod.rs @@ -97,16 +97,22 @@ pub struct Label { /// A pointer to the delegate for this view. pub delegate: Option>, - + /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -136,14 +142,16 @@ impl Label { Label { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: unsafe { ShareId::from_ptr(view) }, } } @@ -165,14 +173,16 @@ impl Label where T: LabelDelegate + 'static { let mut label = Label { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![label, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![label, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![label, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![label, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![label, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![label, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![label, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![label, centerYAnchor] }), + top: LayoutAnchorY::top(label), + left: LayoutAnchorX::left(label), + leading: LayoutAnchorX::leading(label), + right: LayoutAnchorX::right(label), + trailing: LayoutAnchorX::trailing(label), + bottom: LayoutAnchorY::bottom(label), + width: LayoutAnchorDimension::width(label), + height: LayoutAnchorDimension::height(label), + center_x: LayoutAnchorX::center(label), + center_y: LayoutAnchorY::center(label), objc: unsafe { ShareId::from_ptr(label) }, }; @@ -192,7 +202,9 @@ impl Label { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(), diff --git a/src/view/mod.rs b/src/view/mod.rs index 2833911..dfa5f76 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -107,9 +107,15 @@ pub struct View { /// A pointer to the Objective-C runtime leading layout constraint. pub leading: LayoutAnchorX, + /// A pointer to the Objective-C runtime left layout constraint. + pub left: LayoutAnchorX, + /// A pointer to the Objective-C runtime trailing layout constraint. pub trailing: LayoutAnchorX, + /// A pointer to the Objective-C runtime right layout constraint. + pub right: LayoutAnchorX, + /// A pointer to the Objective-C runtime bottom layout constraint. pub bottom: LayoutAnchorY, @@ -139,14 +145,16 @@ impl View { View { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: Rc::new(RefCell::new(unsafe { Id::from_ptr(view) })), } } @@ -169,14 +177,16 @@ impl View where T: ViewDelegate + 'static { let mut view = View { delegate: None, - top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), - leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), - trailing: LayoutAnchorX::new(unsafe { msg_send![view, trailingAnchor] }), - bottom: LayoutAnchorY::new(unsafe { msg_send![view, bottomAnchor] }), - width: LayoutAnchorDimension::new(unsafe { msg_send![view, widthAnchor] }), - height: LayoutAnchorDimension::new(unsafe { msg_send![view, heightAnchor] }), - center_x: LayoutAnchorX::new(unsafe { msg_send![view, centerXAnchor] }), - center_y: LayoutAnchorY::new(unsafe { msg_send![view, centerYAnchor] }), + top: LayoutAnchorY::top(view), + left: LayoutAnchorX::left(view), + leading: LayoutAnchorX::leading(view), + right: LayoutAnchorX::right(view), + trailing: LayoutAnchorX::trailing(view), + bottom: LayoutAnchorY::bottom(view), + width: LayoutAnchorDimension::width(view), + height: LayoutAnchorDimension::height(view), + center_x: LayoutAnchorX::center(view), + center_y: LayoutAnchorY::center(view), objc: Rc::new(RefCell::new(unsafe { Id::from_ptr(view) })), }; @@ -196,7 +206,9 @@ impl View { delegate: None, top: self.top.clone(), leading: self.leading.clone(), + left: self.left.clone(), trailing: self.trailing.clone(), + right: self.right.clone(), bottom: self.bottom.clone(), width: self.width.clone(), height: self.height.clone(),