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.
This commit is contained in:
parent
696907aa73
commit
9446092169
|
@ -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) },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,9 +51,15 @@ pub struct ImageView {
|
|||
/// 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) },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,9 +96,15 @@ pub struct TextField<T = ()> {
|
|||
/// 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<T> TextField<T> 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<T> TextField<T> {
|
|||
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(),
|
||||
|
|
|
@ -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<ShareId<Object>>);
|
||||
pub struct LayoutAnchorDimension2(pub Option<ShareId<Object>>);
|
||||
|
||||
/// 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<Object>),
|
||||
|
||||
/// Represents a Height anchor.
|
||||
Height(ShareId<Object>)
|
||||
}
|
||||
|
||||
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 constraints with an uninitialized anchor!"); }
|
||||
panic!("Attempted to create a constant constraint 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<F>(&self, anchor_to: &LayoutAnchorDimension, handler: F) -> LayoutConstraint
|
||||
where
|
||||
F: Fn(&ShareId<Object>, &ShareId<Object>) -> 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.constraint_with(anchor_to, |from, to| 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!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.constraint_with(anchor_to, |from, to| 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!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ShareId<Object>>);
|
||||
/// 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<Object>),
|
||||
|
||||
/// Represents a left anchor.
|
||||
Left(ShareId<Object>),
|
||||
|
||||
/// Represents a trailing anchor; side depends on system orientation.
|
||||
Trailing(ShareId<Object>),
|
||||
|
||||
/// Represents a right anchor.
|
||||
Right(ShareId<Object>),
|
||||
|
||||
/// Represents a center anchor on the X axis.
|
||||
Center(ShareId<Object>)
|
||||
}
|
||||
|
||||
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<F>(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint
|
||||
where
|
||||
F: Fn(&ShareId<Object>, &ShareId<Object>) -> 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create horizontal constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Object>;
|
||||
|
||||
/// This trait should implement adding a view to the subview tree for a given view.
|
||||
fn add_subview<V: Layout>(&self, _view: &V);
|
||||
/// This trait method should implement adding a view to the subview tree for a given view.
|
||||
fn add_subview<V: Layout>(&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<R: Into<CGRect>>(&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
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ShareId<Object>>);
|
||||
/// 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<Object>),
|
||||
|
||||
/// Represents a bottom anchor.
|
||||
Bottom(ShareId<Object>),
|
||||
|
||||
/// Represents a center anchor for the Y axis.
|
||||
Center(ShareId<Object>)
|
||||
}
|
||||
|
||||
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<F>(&self, anchor_to: &LayoutAnchorY, handler: F) -> LayoutConstraint
|
||||
where
|
||||
F: Fn(&ShareId<Object>, &ShareId<Object>) -> 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create vertical constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.constraint_with(anchor_to, |from, to| unsafe {
|
||||
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to]
|
||||
}),
|
||||
|
||||
_ => { panic!("Attempted to create vertical constraints with an uninitialized anchor!"); }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,9 +200,15 @@ pub struct ListView<T = ()> {
|
|||
/// 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<T> ListView<T> 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<T> ListView<T> 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<T> ListView<T> {
|
|||
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(),
|
||||
|
|
|
@ -99,9 +99,15 @@ pub struct ListViewRow<T = ()> {
|
|||
/// 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<T> ListViewRow<T> 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<T> ListViewRow<T> 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<T> ListViewRow<T> 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<T> ListViewRow<T> {
|
|||
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(),
|
||||
|
|
|
@ -36,28 +36,34 @@ pub struct ProgressIndicator {
|
|||
/// A pointer to the Objective-C Object.
|
||||
pub objc: ShareId<Object>,
|
||||
|
||||
/// 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) },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,9 +101,15 @@ pub struct ScrollView<T = ()> {
|
|||
/// 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<T> ScrollView<T> 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<T> ScrollView<T> {
|
|||
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(),
|
||||
|
|
|
@ -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) },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,9 +104,15 @@ pub struct Label<T = ()> {
|
|||
/// 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<T> Label<T> 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<T> Label<T> {
|
|||
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(),
|
||||
|
|
|
@ -107,9 +107,15 @@ pub struct View<T = ()> {
|
|||
/// 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<T> View<T> 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<T> View<T> {
|
|||
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(),
|
||||
|
|
Loading…
Reference in a new issue