use crate::dnd::DragResult;
use crate::prelude::WxWidget;
use std::boxed::Box;
use std::ffi::{CStr, c_void};
use std::os::raw::c_char;
use wxdragon_sys as ffi;
type DragCallback = Box<dyn FnMut(i32, i32, DragResult) -> DragResult + 'static>;
type LeaveCallback = Box<dyn FnMut() + 'static>;
type DropCallback = Box<dyn FnMut(i32, i32) -> bool + 'static>;
type DropTextCallback = Box<dyn FnMut(&str, i32, i32) -> bool + 'static>;
type DropFilesCallback = Box<dyn FnMut(Vec<String>, i32, i32) -> bool + 'static>;
struct TextDropTargetCallbacks {
on_enter: Option<DragCallback>,
on_drag_over: Option<DragCallback>,
on_leave: Option<LeaveCallback>,
on_drop: Option<DropCallback>,
on_data: Option<DragCallback>,
on_drop_text: DropTextCallback,
}
impl Drop for TextDropTargetCallbacks {
fn drop(&mut self) {
log::debug!("Dropping TextDropTargetCallbacks");
}
}
#[derive(Debug)]
pub struct TextDropTarget {
_obj: *mut ffi::wxd_TextDropTarget_t,
}
pub struct TextDropTargetBuilder<'a, W: WxWidget> {
window: &'a W,
on_enter: Option<DragCallback>,
on_drag_over: Option<DragCallback>,
on_leave: Option<LeaveCallback>,
on_drop: Option<DropCallback>,
on_data: Option<DragCallback>,
on_drop_text: Option<DropTextCallback>,
}
impl<'a, W: WxWidget> TextDropTargetBuilder<'a, W> {
fn new(window: &'a W) -> Self {
Self {
window,
on_enter: None,
on_drag_over: None,
on_leave: None,
on_drop: None,
on_data: None,
on_drop_text: None,
}
}
pub fn with_on_enter<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_enter = Some(Box::new(callback));
self
}
pub fn with_on_drag_over<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_drag_over = Some(Box::new(callback));
self
}
pub fn with_on_leave<F>(mut self, callback: F) -> Self
where
F: FnMut() + 'static,
{
self.on_leave = Some(Box::new(callback));
self
}
pub fn with_on_drop<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32) -> bool + 'static,
{
self.on_drop = Some(Box::new(callback));
self
}
pub fn with_on_data<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_data = Some(Box::new(callback));
self
}
pub fn with_on_drop_text<F>(mut self, callback: F) -> Self
where
F: FnMut(&str, i32, i32) -> bool + 'static,
{
self.on_drop_text = Some(Box::new(callback));
self
}
pub fn build(self) -> TextDropTarget {
let on_drop_text = self.on_drop_text.expect("on_drop_text callback is required");
let callbacks = TextDropTargetCallbacks {
on_enter: self.on_enter,
on_drag_over: self.on_drag_over,
on_leave: self.on_leave,
on_drop: self.on_drop,
on_data: self.on_data,
on_drop_text,
};
let data = Box::new(callbacks);
let data_ptr = Box::into_raw(data);
let user_data = data_ptr as *mut c_void;
let _obj = unsafe {
ffi::wxd_TextDropTarget_CreateFull(
self.window.handle_ptr(),
Some(text_on_enter_trampoline),
Some(text_on_drag_over_trampoline),
Some(text_on_leave_trampoline),
Some(text_on_drop_trampoline),
Some(text_on_data_trampoline),
Some(text_on_drop_text_trampoline),
user_data,
Some(free_text_drop_target_userdata),
)
};
TextDropTarget { _obj }
}
}
impl TextDropTarget {
pub fn builder<W: WxWidget>(window: &W) -> TextDropTargetBuilder<'_, W> {
TextDropTargetBuilder::new(window)
}
}
struct FileDropTargetCallbacks {
on_enter: Option<DragCallback>,
on_drag_over: Option<DragCallback>,
on_leave: Option<LeaveCallback>,
on_drop: Option<DropCallback>,
on_data: Option<DragCallback>,
on_drop_files: DropFilesCallback,
}
impl Drop for FileDropTargetCallbacks {
fn drop(&mut self) {
log::debug!("Dropping FileDropTargetCallbacks");
}
}
#[derive(Debug)]
pub struct FileDropTarget {
_obj: *mut ffi::wxd_FileDropTarget_t,
}
pub struct FileDropTargetBuilder<'a, W: WxWidget> {
window: &'a W,
on_enter: Option<DragCallback>,
on_drag_over: Option<DragCallback>,
on_leave: Option<LeaveCallback>,
on_drop: Option<DropCallback>,
on_data: Option<DragCallback>,
on_drop_files: Option<DropFilesCallback>,
}
impl<'a, W: WxWidget> FileDropTargetBuilder<'a, W> {
fn new(window: &'a W) -> Self {
Self {
window,
on_enter: None,
on_drag_over: None,
on_leave: None,
on_drop: None,
on_data: None,
on_drop_files: None,
}
}
pub fn with_on_enter<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_enter = Some(Box::new(callback));
self
}
pub fn with_on_drag_over<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_drag_over = Some(Box::new(callback));
self
}
pub fn with_on_leave<F>(mut self, callback: F) -> Self
where
F: FnMut() + 'static,
{
self.on_leave = Some(Box::new(callback));
self
}
pub fn with_on_drop<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32) -> bool + 'static,
{
self.on_drop = Some(Box::new(callback));
self
}
pub fn with_on_data<F>(mut self, callback: F) -> Self
where
F: FnMut(i32, i32, DragResult) -> DragResult + 'static,
{
self.on_data = Some(Box::new(callback));
self
}
pub fn with_on_drop_files<F>(mut self, callback: F) -> Self
where
F: FnMut(Vec<String>, i32, i32) -> bool + 'static,
{
self.on_drop_files = Some(Box::new(callback));
self
}
pub fn build(self) -> FileDropTarget {
let on_drop_files = self.on_drop_files.expect("on_drop_files callback is required");
let callbacks = FileDropTargetCallbacks {
on_enter: self.on_enter,
on_drag_over: self.on_drag_over,
on_leave: self.on_leave,
on_drop: self.on_drop,
on_data: self.on_data,
on_drop_files,
};
let data = Box::new(callbacks);
let data_ptr = Box::into_raw(data);
let user_data = data_ptr as *mut c_void;
let _obj = unsafe {
ffi::wxd_FileDropTarget_CreateFull(
self.window.handle_ptr(),
Some(file_on_enter_trampoline),
Some(file_on_drag_over_trampoline),
Some(file_on_leave_trampoline),
Some(file_on_drop_trampoline),
Some(file_on_data_trampoline),
Some(file_on_drop_files_trampoline),
user_data,
Some(free_file_drop_target_userdata),
)
};
FileDropTarget { _obj }
}
}
impl FileDropTarget {
pub fn builder<W: WxWidget>(window: &W) -> FileDropTargetBuilder<'_, W> {
FileDropTargetBuilder::new(window)
}
}
extern "C" fn text_on_enter_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_enter {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn text_on_drag_over_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_drag_over {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn text_on_leave_trampoline(data_ptr: *mut c_void) {
if data_ptr.is_null() {
return;
}
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_leave {
callback();
}
}
extern "C" fn text_on_drop_trampoline(x: i32, y: i32, data_ptr: *mut c_void) -> bool {
if data_ptr.is_null() {
return false;
}
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_drop {
callback(x, y)
} else {
true }
}
extern "C" fn text_on_data_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_data {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn text_on_drop_text_trampoline(text: *const c_char, x: i32, y: i32, data_ptr: *mut c_void) -> bool {
if text.is_null() || data_ptr.is_null() {
return false;
}
let text_str = unsafe { CStr::from_ptr(text).to_string_lossy().into_owned() };
let callbacks = unsafe { &mut *(data_ptr as *mut TextDropTargetCallbacks) };
(callbacks.on_drop_text)(&text_str, x, y)
}
extern "C" fn file_on_enter_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_enter {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn file_on_drag_over_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_drag_over {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn file_on_leave_trampoline(data_ptr: *mut c_void) {
if data_ptr.is_null() {
return;
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_leave {
callback();
}
}
extern "C" fn file_on_drop_trampoline(x: i32, y: i32, data_ptr: *mut c_void) -> bool {
if data_ptr.is_null() {
return false;
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_drop {
callback(x, y)
} else {
true }
}
extern "C" fn file_on_data_trampoline(
x: i32,
y: i32,
def_result: ffi::wxd_DragResult,
data_ptr: *mut c_void,
) -> ffi::wxd_DragResult {
if data_ptr.is_null() {
return def_result;
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
if let Some(ref mut callback) = callbacks.on_data {
callback(x, y, DragResult::from(def_result)).into()
} else {
def_result
}
}
extern "C" fn file_on_drop_files_trampoline(
filenames_ptr: *const ffi::wxd_ArrayString_t,
x: i32,
y: i32,
data_ptr: *mut c_void,
) -> bool {
if filenames_ptr.is_null() || data_ptr.is_null() {
return false;
}
let mut filenames = Vec::<String>::new();
let count = unsafe { ffi::wxd_ArrayString_GetCount(filenames_ptr) };
filenames.reserve(count as usize);
for i in 0..count {
let mut buffer = vec![0; 2048]; let len = unsafe { ffi::wxd_ArrayString_GetString(filenames_ptr, i, buffer.as_mut_ptr(), buffer.len()) };
if len > 0 {
let s = unsafe { CStr::from_ptr(buffer.as_ptr()).to_string_lossy().to_string() };
filenames.push(s);
}
}
let callbacks = unsafe { &mut *(data_ptr as *mut FileDropTargetCallbacks) };
(callbacks.on_drop_files)(filenames, x, y)
}
extern "C" fn free_text_drop_target_userdata(ptr: *mut c_void) {
if ptr.is_null() {
return;
}
let _ = unsafe { Box::from_raw(ptr as *mut TextDropTargetCallbacks) };
}
extern "C" fn free_file_drop_target_userdata(ptr: *mut c_void) {
if ptr.is_null() {
return;
}
let _ = unsafe { Box::from_raw(ptr as *mut FileDropTargetCallbacks) };
}