use std::sync::Once;
use core_graphics::geometry::CGRect;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use crate::control::Control;
use crate::foundation::{id, nil, NSInteger, NSString, NO, YES};
use crate::geometry::Rect;
use crate::invoker::TargetActionHandler;
use crate::layout::Layout;
use crate::objc_access::ObjcAccess;
use crate::utils::properties::ObjcProperty;
#[cfg(feature = "autolayout")]
use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY};
#[derive(Debug)]
pub struct Select {
pub objc: ObjcProperty,
handler: Option<TargetActionHandler>,
#[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 Select {
pub fn new() -> Self {
let zero: CGRect = Rect::zero().into();
let view: id = unsafe {
let alloc: id = msg_send![register_class(), alloc];
let select: id = msg_send![alloc, initWithFrame:zero pullsDown:NO];
#[cfg(feature = "autolayout")]
let _: () = msg_send![select, setTranslatesAutoresizingMaskIntoConstraints: NO];
select
};
Select {
handler: None,
#[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),
objc: ObjcProperty::retain(view)
}
}
pub fn set_action<F: Fn() + Send + Sync + 'static>(&mut self, action: F) {
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) });
let handler = TargetActionHandler::new(&*this, action);
self.handler = Some(handler);
}
pub fn set_pulls_down(&self, pulls_down: bool) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setPullsDown:match pulls_down {
true => YES,
false => NO
}];
});
}
pub fn add_item(&self, title: &str) {
self.objc.with_mut(|obj| unsafe {
let s = NSString::new(title);
let _: () = msg_send![obj, addItemWithTitle: s];
});
}
pub fn remove_all_items(&self) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, removeAllItems];
});
}
pub fn remove_item_at_index(&self, index: usize) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, removeItemAtIndex: index];
});
}
pub fn set_selected_index(&self, index: NSInteger) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, selectItemAtIndex: index];
});
}
pub fn get_selected_index(&self) -> usize {
self.objc.get(|obj| unsafe {
let index: NSInteger = msg_send![obj, indexOfSelectedItem];
index as usize
})
}
pub fn len(&self) -> usize {
self.objc.get(|obj| unsafe {
let index: NSInteger = msg_send![obj, numberOfItems];
index as usize
})
}
}
impl ObjcAccess for Select {
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 Layout for Select {
fn add_subview<V: Layout>(&self, _view: &V) {
panic!(
r#"
Tried to add a subview to a Select. This is not allowed in Cacao. If you think this should be supported,
open a discussion on the GitHub repo.
"#
);
}
}
impl Control for Select {}
impl ObjcAccess for &Select {
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 Layout for &Select {
fn add_subview<V: Layout>(&self, _view: &V) {
panic!(
r#"
Tried to add a subview to a Select. This is not allowed in Cacao. If you think this should be supported,
open a discussion on the GitHub repo.
"#
);
}
}
impl Control for &Select {}
impl Drop for Select {
fn drop(&mut self) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setTarget: nil];
let _: () = msg_send![obj, setAction: nil];
});
}
}
fn register_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(NSPopUpButton);
let decl = ClassDecl::new("CacaoSelect", superclass).unwrap();
VIEW_CLASS = decl.register();
});
unsafe { VIEW_CLASS }
}