use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use crate::foundation::id;
use crate::layout::constraint::LayoutConstraint;
#[derive(Clone, Debug)]
pub enum LayoutAnchorX {
Uninitialized,
Leading(ShareId<Object>),
Left(ShareId<Object>),
Trailing(ShareId<Object>),
Right(ShareId<Object>),
Center(ShareId<Object>)
}
impl Default for LayoutAnchorX {
fn default() -> Self {
Self::Uninitialized
}
}
impl LayoutAnchorX {
pub(crate) fn leading(view: id) -> Self {
Self::Leading(unsafe { ShareId::from_ptr(msg_send![view, leadingAnchor]) })
}
pub(crate) fn left(view: id) -> Self {
Self::Left(unsafe { ShareId::from_ptr(msg_send![view, leftAnchor]) })
}
pub(crate) fn trailing(view: id) -> Self {
Self::Trailing(unsafe { ShareId::from_ptr(msg_send![view, trailingAnchor]) })
}
pub(crate) fn right(view: id) -> Self {
Self::Right(unsafe { ShareId::from_ptr(msg_send![view, rightAnchor]) })
}
pub(crate) fn center(view: id) -> Self {
Self::Center(unsafe { ShareId::from_ptr(msg_send![view, centerXAnchor]) })
}
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint
where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id
{
match (self, anchor_to) {
(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)),
(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.
"#
);
},
(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.");
}
}
}
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintEqualToAnchor:&**to]
})
}
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to]
})
}
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to]
})
}
}