Skip to content

Commit

Permalink
Working drag and drop for Mac OS
Browse files Browse the repository at this point in the history
  • Loading branch information
ilmai committed Jun 20, 2023
1 parent 1921d47 commit 8270260
Showing 1 changed file with 55 additions and 41 deletions.
96 changes: 55 additions & 41 deletions src/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
};

use super::{NSDragOperationGeneric, NSDragOperationCopy, NSDragOperationMove, NSDragOperationLink, NSDragOperationNone};
use super::keyboard::make_modifiers;
use super::keyboard::{make_modifiers, from_nsstring};
use super::window::WindowState;

/// Name of the field used to store the `WindowState` pointer.
Expand Down Expand Up @@ -403,7 +403,26 @@ fn get_drag_position(sender: id) -> Point {
}

fn get_drop_data(sender: id) -> DropData {
DropData::None
if sender == nil {
return DropData::None;
}

unsafe {
let pasteboard: id = msg_send![sender, draggingPasteboard];
let file_list: id = msg_send![pasteboard, propertyListForType: NSFilenamesPboardType];

if file_list == nil {
return DropData::None;
}

let mut files = vec![];
for i in 0..NSArray::count(file_list) {
let data = NSArray::objectAtIndex(file_list, i);
files.push(from_nsstring(data).into());
}

DropData::Files(files)
}
}

fn on_event(window_state: &mut WindowState, event: MouseEvent) -> NSUInteger {
Expand Down Expand Up @@ -431,54 +450,49 @@ extern "C" fn dragging_entered(this: &Object, _sel: Sel, sender: id) -> NSUInteg
on_event(state, event)
}

extern "C" fn dragging_updated(this: &Object, _sel: Sel, dragging_info: id) -> NSUInteger {
if let Some(drag_info) = unsafe { get_drag_info(dragging_info) } {
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
let event = WindowEvent::DragUpdated(drag_info);
state.trigger_event(Event::Window(event));
}
4 // NSDragOperationGeneric
}
extern "C" fn dragging_updated(this: &Object, _sel: Sel, sender: id) -> NSUInteger {
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
let modifiers = state.keyboard_state().last_mods();
let drop_data = get_drop_data(sender);

extern "C" fn prepare_for_drag_operation(_this: &Object, _sel: Sel, _dragging_info: id) -> BOOL {
YES
let event = MouseEvent::DragMoved {
position: get_drag_position(sender),
modifiers: make_modifiers(modifiers),
data: drop_data,
};

on_event(state, event)
}

extern "C" fn perform_drag_operation(this: &Object, _sel: Sel, dragging_info: id) -> BOOL {
if let Some(drag_info) = unsafe { get_drag_info(dragging_info) } {
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
let event = WindowEvent::DragPerformed(drag_info);
state.trigger_event(Event::Window(event));
}
extern "C" fn prepare_for_drag_operation(_this: &Object, _sel: Sel, sender: id) -> BOOL {
// Always accept drag operation if we get this far
// This function won't be called unless dragging_entered/updated
// has returned an acceptable operation
YES
}

extern "C" fn dragging_exited(this: &Object, _sel: Sel, dragging_info: id) {
let drag_info = unsafe { get_drag_info(dragging_info) };
extern "C" fn perform_drag_operation(this: &Object, _sel: Sel, sender: id) -> BOOL {
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
let event = WindowEvent::DragExited(drag_info);
state.trigger_event(Event::Window(event));
}

unsafe fn get_drag_info(dragging_info: id) -> Option<DragInfo> {
if dragging_info == nil {
return None;
}
let modifiers = state.keyboard_state().last_mods();
let drop_data = get_drop_data(sender);

let pasteboard: id = msg_send![dragging_info, draggingPasteboard];
let file_list: id = msg_send![pasteboard, propertyListForType: NSFilenamesPboardType];
let event = MouseEvent::DragDropped {
position: get_drag_position(sender),
modifiers: make_modifiers(modifiers),
data: drop_data,
};

if file_list == nil {
return None;
let event_status = state.trigger_event(Event::Mouse(event));
match event_status {
EventStatus::AcceptDrop(_) => YES,
_ => NO,
}
}

let mut file_vec: Vec<String> = vec![];
let count = NSArray::count(file_list);
if count > 0 {
let data = NSArray::objectAtIndex(file_list, 0);
let str = from_nsstring(data);
file_vec.push(str);
}
extern "C" fn dragging_exited(this: &Object, _sel: Sel, sender: id) {
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
let modifiers = state.keyboard_state().last_mods();
let drop_data = get_drop_data(sender);

Some(DragInfo::FilesDragged { files: file_vec })
}
on_event(state, MouseEvent::DragLeft);
}

0 comments on commit 8270260

Please sign in to comment.