use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use crate::color::Color;
use crate::control::Control;
use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NO, YES};
use crate::layout::Layout;
use crate::objc_access::ObjcAccess;
use crate::text::{Font, TextAlign};
use crate::utils::properties::ObjcProperty;
#[cfg(feature = "autolayout")]
use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY};
#[cfg(feature = "appkit")]
mod appkit;
#[cfg(feature = "appkit")]
use appkit::{register_view_class, register_view_class_with_delegate};
mod traits;
pub use traits::TextFieldDelegate;
pub(crate) static TEXTFIELD_DELEGATE_PTR: &str = "rstTextFieldDelegatePtr";
fn common_init(class: *const Class) -> id {
unsafe {
let view: id = msg_send![class, new];
#[cfg(feature = "autolayout")]
let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints: NO];
#[cfg(feature = "appkit")]
let _: () = msg_send![view, setWantsLayer: YES];
view
}
}
#[derive(Debug)]
pub struct TextField<T = ()> {
pub objc: ObjcProperty,
pub delegate: Option<Box<T>>,
#[cfg(feature = "autolayout")]
pub top: LayoutAnchorY,
#[cfg(feature = "autolayout")]
pub leading: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub left: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub trailing: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub right: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub bottom: LayoutAnchorY,
#[cfg(feature = "autolayout")]
pub width: LayoutAnchorDimension,
#[cfg(feature = "autolayout")]
pub height: LayoutAnchorDimension,
#[cfg(feature = "autolayout")]
pub center_x: LayoutAnchorX,
#[cfg(feature = "autolayout")]
pub center_y: LayoutAnchorY
}
impl Default for TextField {
fn default() -> Self {
TextField::new()
}
}
impl TextField {
pub fn new() -> Self {
let class = register_view_class();
let view = common_init(class);
TextField {
delegate: None,
objc: ObjcProperty::retain(view),
#[cfg(feature = "autolayout")]
top: LayoutAnchorY::top(view),
#[cfg(feature = "autolayout")]
left: LayoutAnchorX::left(view),
#[cfg(feature = "autolayout")]
leading: LayoutAnchorX::leading(view),
#[cfg(feature = "autolayout")]
right: LayoutAnchorX::right(view),
#[cfg(feature = "autolayout")]
trailing: LayoutAnchorX::trailing(view),
#[cfg(feature = "autolayout")]
bottom: LayoutAnchorY::bottom(view),
#[cfg(feature = "autolayout")]
width: LayoutAnchorDimension::width(view),
#[cfg(feature = "autolayout")]
height: LayoutAnchorDimension::height(view),
#[cfg(feature = "autolayout")]
center_x: LayoutAnchorX::center(view),
#[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(view)
}
}
}
impl<T> TextField<T>
where
T: TextFieldDelegate + 'static
{
pub fn with(delegate: T) -> TextField<T> {
let class = register_view_class_with_delegate(&delegate);
let mut delegate = Box::new(delegate);
let label = common_init(class);
unsafe {
let ptr: *const T = &*delegate;
(&mut *label).set_ivar(TEXTFIELD_DELEGATE_PTR, ptr as usize);
};
let mut label = TextField {
delegate: None,
objc: ObjcProperty::retain(label),
#[cfg(feature = "autolayout")]
top: LayoutAnchorY::top(label),
#[cfg(feature = "autolayout")]
left: LayoutAnchorX::left(label),
#[cfg(feature = "autolayout")]
leading: LayoutAnchorX::leading(label),
#[cfg(feature = "autolayout")]
right: LayoutAnchorX::right(label),
#[cfg(feature = "autolayout")]
trailing: LayoutAnchorX::trailing(label),
#[cfg(feature = "autolayout")]
bottom: LayoutAnchorY::bottom(label),
#[cfg(feature = "autolayout")]
width: LayoutAnchorDimension::width(label),
#[cfg(feature = "autolayout")]
height: LayoutAnchorDimension::height(label),
#[cfg(feature = "autolayout")]
center_x: LayoutAnchorX::center(label),
#[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(label)
};
(&mut delegate).did_load(label.clone_as_handle());
label.delegate = Some(delegate);
label
}
}
impl<T> TextField<T> {
pub(crate) fn clone_as_handle(&self) -> TextField {
TextField {
delegate: None,
objc: self.objc.clone(),
#[cfg(feature = "autolayout")]
top: self.top.clone(),
#[cfg(feature = "autolayout")]
leading: self.leading.clone(),
#[cfg(feature = "autolayout")]
left: self.left.clone(),
#[cfg(feature = "autolayout")]
trailing: self.trailing.clone(),
#[cfg(feature = "autolayout")]
right: self.right.clone(),
#[cfg(feature = "autolayout")]
bottom: self.bottom.clone(),
#[cfg(feature = "autolayout")]
width: self.width.clone(),
#[cfg(feature = "autolayout")]
height: self.height.clone(),
#[cfg(feature = "autolayout")]
center_x: self.center_x.clone(),
#[cfg(feature = "autolayout")]
center_y: self.center_y.clone()
}
}
pub fn get_value(&self) -> String {
self.objc
.get(|obj| unsafe { NSString::retain(msg_send![obj, stringValue]).to_string() })
}
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
self.objc.with_mut(|obj| unsafe {
let cg = color.as_ref().cg_color();
let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: cg];
});
}
pub fn set_text(&self, text: &str) {
let s = NSString::new(text);
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setStringValue:&*s];
});
}
pub fn set_placeholder_text(&self, text: &str) {
let s = NSString::new(text);
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setPlaceholderString:&*s];
});
}
pub fn set_text_alignment(&self, alignment: TextAlign) {
self.objc.with_mut(|obj| unsafe {
let alignment: NSInteger = alignment.into();
let _: () = msg_send![obj, setAlignment: alignment];
});
}
pub fn set_uses_single_line(&self, uses_single_line: bool) {
self.objc.with_mut(|obj| unsafe {
let cell: id = msg_send![obj, cell];
let _: () = msg_send![cell, setUsesSingleLineMode:match uses_single_line {
true => YES,
false => NO
}];
});
}
pub fn set_wraps(&self, uses_single_line: bool) {
self.objc.with_mut(|obj| unsafe {
let cell: id = msg_send![obj, cell];
let _: () = msg_send![cell, setWraps:match uses_single_line {
true => YES,
false => NO
}];
});
}
pub fn set_max_number_of_lines(&self, num: NSInteger) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setMaximumNumberOfLines: num];
});
}
pub fn set_font<F: AsRef<Font>>(&self, font: F) {
let font = font.as_ref().clone();
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setFont:&*font];
});
}
}
impl<T> ObjcAccess for TextField<T> {
fn with_backing_obj_mut<F: Fn(id)>(&self, handler: F) {
self.objc.with_mut(handler);
}
fn get_from_backing_obj<F: Fn(&Object) -> R, R>(&self, handler: F) -> R {
self.objc.get(handler)
}
}
impl<T> Layout for TextField<T> {}
impl<T> Control for TextField<T> {}
impl<T> Drop for TextField<T> {
fn drop(&mut self) {
}
}