use std::ffi::c_void;
use super::super::{
CgPoint, CgRect, CgSize, Class, Id, Sel, class, class_addMethod, msg_id, msg_id_id, msg_void,
msg_void_id, nsstring, objc_msgSend, sel,
};
use super::DRAG_OPERATION_COPY;
use crate::platform::DropData;
const ICON: f64 = 32.0;
pub(in super::super) unsafe fn add_methods(cls: Class) {
unsafe {
class_addMethod(
cls,
sel("draggingSession:sourceOperationMaskForDraggingContext:"),
operation_mask as *const c_void,
c"Q@:@q".as_ptr(),
);
}
}
extern "C" fn operation_mask(_this: Id, _cmd: Sel, _session: Id, _context: i64) -> u64 {
DRAG_OPERATION_COPY
}
pub(in super::super) unsafe fn begin(view: Id, event: Id, data: &DropData) -> bool {
unsafe {
let point: unsafe extern "C" fn(Id, Sel) -> CgPoint =
std::mem::transmute(objc_msgSend as *const c_void);
let convert: unsafe extern "C" fn(Id, Sel, CgPoint, Id) -> CgPoint =
std::mem::transmute(objc_msgSend as *const c_void);
let set_frame: unsafe extern "C" fn(Id, Sel, CgRect, Id) =
std::mem::transmute(objc_msgSend as *const c_void);
let begin: unsafe extern "C" fn(Id, Sel, Id, Id, Id) -> Id =
std::mem::transmute(objc_msgSend as *const c_void);
let in_window = point(event, sel("locationInWindow"));
let at = convert(
view,
sel("convertPoint:fromView:"),
in_window,
std::ptr::null_mut(),
);
let workspace = msg_id(class("NSWorkspace"), sel("sharedWorkspace"));
let mut writers: Vec<(Id, Id)> = Vec::new();
match data {
DropData::Files(paths) => {
for path in paths {
let path = nsstring(&path.to_string_lossy());
let url = msg_id_id(class("NSURL"), sel("fileURLWithPath:"), path);
let icon = msg_id_id(workspace, sel("iconForFile:"), path);
if !url.is_null() {
writers.push((url, icon));
}
}
}
DropData::Text(text) => {
let icon = msg_id_id(workspace, sel("iconForFileType:"), nsstring("txt"));
writers.push((nsstring(text), icon));
}
DropData::Internal(_) => {}
}
if writers.is_empty() {
return false;
}
let items = msg_id(class("NSMutableArray"), sel("array"));
for (i, (writer, icon)) in writers.into_iter().enumerate() {
let item = msg_id_id(
msg_id(class("NSDraggingItem"), sel("alloc")),
sel("initWithPasteboardWriter:"),
writer,
);
if item.is_null() {
continue;
}
let step = 4.0 * i.min(4) as f64;
let frame = CgRect {
origin: CgPoint {
x: at.x - ICON / 2.0 + step,
y: at.y - ICON / 2.0 + step,
},
size: CgSize {
width: ICON,
height: ICON,
},
};
set_frame(item, sel("setDraggingFrame:contents:"), frame, icon);
msg_void_id(items, sel("addObject:"), item);
msg_void(item, sel("release"));
}
let session = begin(
view,
sel("beginDraggingSessionWithItems:event:source:"),
items,
event,
view,
);
!session.is_null()
}
}