use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use crate::dragdrop::DragInfo;
use crate::foundation::{id, nil, NSUInteger, NO, YES};
use crate::listview::row::{ViewDelegate, BACKGROUND_COLOR, LISTVIEW_ROW_DELEGATE_PTR};
use crate::utils::load;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL {
return YES;
}
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
})
.into()
}
extern "C" fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}
extern "C" fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}
extern "C" fn conclude_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
});
}
extern "C" fn dragging_exited<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) }
});
}
extern "C" fn update_layer(this: &Object, _: Sel) {
unsafe {
let background_color: id = *this.get_ivar(BACKGROUND_COLOR);
if background_color != nil {
let layer: id = msg_send![this, layer];
let cg: id = msg_send![background_color, CGColor];
let _: () = msg_send![layer, setBackgroundColor: cg];
}
}
}
extern "C" fn dealloc<T: ViewDelegate>(this: &Object, _: Sel) {
unsafe {
let ptr: usize = *(&*this).get_ivar(LISTVIEW_ROW_DELEGATE_PTR);
let obj = ptr as *mut T;
let _x = Box::from_raw(obj);
let _: () = msg_send![super(this, class!(NSView)), dealloc];
}
}
pub(crate) fn register_listview_row_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!(NSView);
let mut decl = ClassDecl::new("RSTTableViewRow", superclass).unwrap();
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL);
VIEW_CLASS = decl.register();
});
unsafe { VIEW_CLASS }
}
pub(crate) fn register_listview_row_class_with_delegate<T: ViewDelegate>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(NSView);
let mut decl = ClassDecl::new("RSTableViewRowWithDelegate", superclass).unwrap();
decl.add_ivar::<usize>(LISTVIEW_ROW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _));
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method(
sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
);
decl.add_method(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(sel!(dealloc), dealloc::<T> as extern "C" fn(&Object, _));
VIEW_CLASS = decl.register();
});
unsafe { VIEW_CLASS }
}