WIP: UI: Add Drag & Drop Feedback on Windows #107056
4
extern/xdnd/CMakeLists.txt
vendored
4
extern/xdnd/CMakeLists.txt
vendored
@ -21,4 +21,8 @@ add_definitions(
|
||||
-DHAVE_SYS_TIME_H
|
||||
)
|
||||
|
||||
if(WITH_INPUT_NDOF)
|
||||
add_definitions(-DWITH_INPUT_NDOF)
|
||||
endif()
|
||||
|
||||
blender_add_lib(extern_xdnd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
432
extern/xdnd/xdnd.c
vendored
432
extern/xdnd/xdnd.c
vendored
@ -627,7 +627,7 @@ static void xdnd_send_status (DndClass * dnd, Window window, Window from, int wi
|
||||
xevent.xany.display = dnd->display;
|
||||
xevent.xclient.window = window;
|
||||
xevent.xclient.message_type = dnd->XdndStatus;
|
||||
xevent.xclient.format = 32;
|
||||
xevent.xclient.format = 32;
|
||||
|
||||
XDND_STATUS_TARGET_WIN (&xevent) = from;
|
||||
XDND_STATUS_WILL_ACCEPT_SET (&xevent, will_accept);
|
||||
@ -1254,183 +1254,6 @@ Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* returns non-zero if event is handled */
|
||||
int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent)
|
||||
{
|
||||
int result = 0;
|
||||
if (xevent->type == SelectionNotify) {
|
||||
dnd_debug1 ("got SelectionNotify");
|
||||
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM && dnd->stage == XDND_DROP_STAGE_CONVERTING) {
|
||||
int error;
|
||||
dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection");
|
||||
error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
|
||||
/* error is not actually used, i think future versions of the protocol maybe should return
|
||||
an error status to the calling window with the XdndFinished client message */
|
||||
if (dnd_version_at_least (dnd->dragging_version, 2)) {
|
||||
#if XDND_VERSION >= 3
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);
|
||||
#else
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);
|
||||
#endif
|
||||
dnd_debug1 (" sending finished");
|
||||
}
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
xdnd_reset (dnd);
|
||||
dnd->stage = XDND_DROP_STAGE_IDLE;
|
||||
result = 1;
|
||||
} else {
|
||||
dnd_debug1 (" property is not Xdnd_NON_PROTOCOL_ATOM - ignoring");
|
||||
}
|
||||
} else if (xevent->type == ClientMessage) {
|
||||
dnd_debug2 ("got ClientMessage to xevent->xany.window = %ld", xevent->xany.window);
|
||||
if (xevent->xclient.message_type == dnd->XdndEnter) {
|
||||
dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));
|
||||
#if XDND_VERSION >= 3
|
||||
if (XDND_ENTER_VERSION (xevent) < 3)
|
||||
return 0;
|
||||
#endif
|
||||
xdnd_reset (dnd);
|
||||
dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);
|
||||
#if XDND_VERSION >= 3
|
||||
dnd->dropper_toplevel = xevent->xany.window;
|
||||
dnd->dropper_window = 0; /* enter goes to the top level window only,
|
||||
so we don't really know what the
|
||||
sub window is yet */
|
||||
#else
|
||||
dnd->dropper_window = xevent->xany.window;
|
||||
#endif
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
if (XDND_ENTER_THREE_TYPES (xevent)) {
|
||||
dnd_debug1 (" three types only");
|
||||
xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist);
|
||||
} else {
|
||||
dnd_debug1 (" more than three types - getting list");
|
||||
xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist);
|
||||
}
|
||||
if (dnd->dragger_typelist)
|
||||
dnd->stage = XDND_DROP_STAGE_ENTERED;
|
||||
else
|
||||
dnd_debug1 (" typelist returned as zero!");
|
||||
dnd->dragging_version = XDND_ENTER_VERSION (xevent);
|
||||
result = 1;
|
||||
} else if (xevent->xclient.message_type == dnd->XdndLeave) {
|
||||
#if XDND_VERSION >= 3
|
||||
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
#endif
|
||||
dnd_debug1 (" message_type is XdndLeave");
|
||||
if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
|
||||
dnd_debug1 (" leaving");
|
||||
if (dnd->widget_apply_leave)
|
||||
(*dnd->widget_apply_leave) (dnd, xevent->xany.window);
|
||||
dnd->stage = XDND_DROP_STAGE_IDLE;
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
result = 1;
|
||||
dnd->dropper_toplevel = dnd->dropper_window = 0;
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
} else if (xevent->xclient.message_type == dnd->XdndPosition) {
|
||||
dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window);
|
||||
if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
|
||||
int want_position;
|
||||
Atom action;
|
||||
XRectangle rectangle;
|
||||
Window last_window;
|
||||
last_window = dnd->dropper_window;
|
||||
#if XDND_VERSION >= 3
|
||||
/* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */
|
||||
if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) {
|
||||
Window parent, child, new_child = 0;
|
||||
dnd->dropper_toplevel = xevent->xany.window;
|
||||
parent = dnd->root_window;
|
||||
child = dnd->dropper_toplevel;
|
||||
for (;;) {
|
||||
int xd, yd;
|
||||
new_child = 0;
|
||||
if (!XTranslateCoordinates (dnd->display, parent, child,
|
||||
XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent),
|
||||
&xd, &yd, &new_child))
|
||||
break;
|
||||
if (!new_child)
|
||||
break;
|
||||
child = new_child;
|
||||
}
|
||||
dnd->dropper_window = xevent->xany.window = child;
|
||||
dnd_debug2 (" child window translates to %ld", dnd->dropper_window);
|
||||
} else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) {
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
dnd_debug2 (" child window previously found: %ld", dnd->dropper_window);
|
||||
}
|
||||
#endif
|
||||
action = dnd->XdndActionCopy;
|
||||
dnd->supported_action = dnd->XdndActionCopy;
|
||||
dnd->x = XDND_POSITION_ROOT_X (xevent);
|
||||
dnd->y = XDND_POSITION_ROOT_Y (xevent);
|
||||
dnd->time = CurrentTime;
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
dnd->time = XDND_POSITION_TIME (xevent);
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
action = XDND_POSITION_ACTION (xevent);
|
||||
#if XDND_VERSION >= 3
|
||||
if (last_window && last_window != xevent->xany.window)
|
||||
if (dnd->widget_apply_leave)
|
||||
(*dnd->widget_apply_leave) (dnd, last_window);
|
||||
#endif
|
||||
dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window,
|
||||
action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist,
|
||||
&want_position, &dnd->supported_action, &dnd->desired_type, &rectangle);
|
||||
dnd_debug2 (" will accept = %d", dnd->will_accept);
|
||||
#if XDND_VERSION >= 3
|
||||
dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel);
|
||||
xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept,
|
||||
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
|
||||
#else
|
||||
dnd_debug2 (" sending status of %ld", xevent->xany.window);
|
||||
xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept,
|
||||
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
|
||||
#endif
|
||||
result = 1;
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
} else if (xevent->xclient.message_type == dnd->XdndDrop) {
|
||||
#if XDND_VERSION >= 3
|
||||
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
#endif
|
||||
dnd_debug1 (" message_type is XdndDrop");
|
||||
if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
|
||||
dnd->time = CurrentTime;
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
dnd->time = XDND_DROP_TIME (xevent);
|
||||
if (dnd->will_accept) {
|
||||
dnd_debug1 (" will_accept is true - converting selectiong");
|
||||
dnd_debug2 (" my window is %ld", dnd->dropper_window);
|
||||
dnd_debug2 (" source window is %ld", dnd->dragger_window);
|
||||
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
|
||||
dnd->stage = XDND_DROP_STAGE_CONVERTING;
|
||||
} else {
|
||||
dnd_debug1 (" will_accept is false - sending finished");
|
||||
if (dnd_version_at_least (dnd->dragging_version, 2)) {
|
||||
#if XDND_VERSION >= 3
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);
|
||||
#else
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);
|
||||
#endif
|
||||
}
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
xdnd_reset (dnd);
|
||||
dnd->stage = XDND_DROP_STAGE_IDLE;
|
||||
}
|
||||
result = 1;
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Following here is a sample implementation: Suppose we want a window
|
||||
@ -1550,50 +1373,241 @@ static int widget_apply_position (DndClass * dnd, Window widgets_window, Window
|
||||
return 1;
|
||||
}
|
||||
|
||||
Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
|
||||
void handle_update(DndClass * dnd, XEvent * xevent){
|
||||
dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window);
|
||||
if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent)) {
|
||||
int want_position;
|
||||
Atom action;
|
||||
XRectangle rectangle;
|
||||
Window last_window;
|
||||
last_window = dnd->dropper_window;
|
||||
#if XDND_VERSION >= 3
|
||||
/* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */
|
||||
if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) {
|
||||
Window parent, child, new_child = 0;
|
||||
dnd->dropper_toplevel = xevent->xany.window;
|
||||
parent = dnd->root_window;
|
||||
child = dnd->dropper_toplevel;
|
||||
for (;;) {
|
||||
int xd, yd;
|
||||
new_child = 0;
|
||||
if (!XTranslateCoordinates (dnd->display, parent, child,
|
||||
XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent),
|
||||
&xd, &yd, &new_child))
|
||||
break;
|
||||
if (!new_child)
|
||||
break;
|
||||
child = new_child;
|
||||
}
|
||||
dnd->dropper_window = xevent->xany.window = child;
|
||||
dnd_debug2 (" child window translates to %ld", dnd->dropper_window);
|
||||
} else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) {
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
dnd_debug2 (" child window previously found: %ld", dnd->dropper_window);
|
||||
}
|
||||
#endif
|
||||
action = dnd->XdndActionCopy;
|
||||
dnd->supported_action = dnd->XdndActionCopy;
|
||||
dnd->x = XDND_POSITION_ROOT_X (xevent);
|
||||
dnd->y = XDND_POSITION_ROOT_Y (xevent);
|
||||
dnd->time = CurrentTime;
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
dnd->time = XDND_POSITION_TIME (xevent);
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
action = XDND_POSITION_ACTION (xevent);
|
||||
#if XDND_VERSION >= 3
|
||||
if (last_window && last_window != xevent->xany.window)
|
||||
if (dnd->widget_apply_leave)
|
||||
(*dnd->widget_apply_leave) (dnd, last_window);
|
||||
#endif
|
||||
dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window,
|
||||
action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist,
|
||||
&want_position, &dnd->supported_action, &dnd->desired_type, &rectangle);
|
||||
dnd_debug2 (" will accept = %d", dnd->will_accept);
|
||||
#if XDND_VERSION >= 3
|
||||
dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel);
|
||||
xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept,
|
||||
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
|
||||
#else
|
||||
dnd_debug2 (" sending status of %ld", xevent->xany.window);
|
||||
xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept,
|
||||
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
|
||||
#endif
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_enter(DndClass * dnd, XEvent * xevent){
|
||||
dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));
|
||||
#if XDND_VERSION >= 3
|
||||
if (XDND_ENTER_VERSION (xevent) < 3)
|
||||
return;
|
||||
#endif
|
||||
xdnd_reset (dnd);
|
||||
dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);
|
||||
#if XDND_VERSION >= 3
|
||||
dnd->dropper_toplevel = xevent->xany.window;
|
||||
dnd->dropper_window = 0; /* enter goes to the top level window only,
|
||||
so we don't really know what the
|
||||
sub window is yet */
|
||||
#else
|
||||
dnd->dropper_window = xevent->xany.window;
|
||||
#endif
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
if (XDND_ENTER_THREE_TYPES (xevent)) {
|
||||
dnd_debug1 (" three types only");
|
||||
xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist);
|
||||
} else {
|
||||
dnd_debug1 (" more than three types - getting list");
|
||||
xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist);
|
||||
}
|
||||
dnd->dragging_version = XDND_ENTER_VERSION (xevent);
|
||||
if (!dnd->dragger_typelist){
|
||||
return;
|
||||
}
|
||||
for (;xevent->xclient.message_type != dnd->XdndPosition;)
|
||||
{
|
||||
XNextEvent(dnd->display, xevent);
|
||||
}
|
||||
handle_update(dnd, xevent);
|
||||
/* Send request for obtain selection data. */
|
||||
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
|
||||
/* Wait to receive selection. */
|
||||
for (;xevent->type != SelectionNotify;)
|
||||
{
|
||||
XNextEvent(dnd->display, xevent);
|
||||
}
|
||||
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM ) {
|
||||
xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_exit(DndClass * dnd, XEvent * xevent){
|
||||
#if XDND_VERSION >= 3
|
||||
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
#endif
|
||||
dnd_debug1 (" message_type is XdndLeave");
|
||||
if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) ) {
|
||||
dnd_debug1 (" leaving");
|
||||
if (dnd->widget_apply_leave)
|
||||
(*dnd->widget_apply_leave) (dnd, xevent->xany.window);
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
dnd->dropper_toplevel = dnd->dropper_window = 0;
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_drop(DndClass * dnd, XEvent * xevent){
|
||||
#if XDND_VERSION >= 3
|
||||
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
|
||||
xevent->xany.window = dnd->dropper_window;
|
||||
#endif
|
||||
dnd_debug1 (" message_type is XdndDrop");
|
||||
if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent)) {
|
||||
dnd->time = CurrentTime;
|
||||
if (dnd_version_at_least (dnd->dragging_version, 1))
|
||||
dnd->time = XDND_DROP_TIME (xevent);
|
||||
if (dnd->will_accept) {
|
||||
dnd_debug1 (" will_accept is true - converting selectiong");
|
||||
dnd_debug2 (" my window is %ld", dnd->dropper_window);
|
||||
dnd_debug2 (" source window is %ld", dnd->dragger_window);
|
||||
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
|
||||
} else {
|
||||
dnd_debug1 (" will_accept is false - sending finished");
|
||||
if (dnd_version_at_least (dnd->dragging_version, 2)) {
|
||||
#if XDND_VERSION >= 3
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);
|
||||
#else
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);
|
||||
#endif
|
||||
}
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
xdnd_reset (dnd);
|
||||
}
|
||||
} else {
|
||||
dnd_debug1 (" wrong stage or from wrong window");
|
||||
}
|
||||
/* Wait to receive selection. */
|
||||
for (;xevent->type != SelectionNotify;)
|
||||
{
|
||||
XNextEvent(dnd->display, xevent);
|
||||
}
|
||||
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM ) {
|
||||
int error;
|
||||
dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection");
|
||||
error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
|
||||
/* error is not actually used, i think future versions of the protocol maybe should return
|
||||
an error status to the calling window with the XdndFinished client message */
|
||||
if (dnd_version_at_least (dnd->dragging_version, 2)) {
|
||||
#if XDND_VERSION >= 3
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);
|
||||
#else
|
||||
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);
|
||||
#endif
|
||||
dnd_debug1 (" sending finished");
|
||||
}
|
||||
xdnd_xfree (dnd->dragger_typelist);
|
||||
xdnd_reset (dnd);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TEventType xdnd_handle_event (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
|
||||
unsigned char **data, int *length, Atom * type, int *x, int *y)
|
||||
{
|
||||
Atom action = 0;
|
||||
GHOST_TEventType event_type = 0;
|
||||
static int initialised = 0;
|
||||
static DndClass dnd;
|
||||
if (!initialised) {
|
||||
xdnd_init (&dnd, display);
|
||||
if (!initialised)
|
||||
{
|
||||
xdnd_init(&dnd, display);
|
||||
initialised = 1;
|
||||
}
|
||||
if (xevent->type != ClientMessage || xevent->xclient.message_type != dnd.XdndEnter) {
|
||||
if (xevent->type != ClientMessage)
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
struct xdnd_get_drop_info i;
|
||||
|
||||
/* setup user structure */
|
||||
memset (&i, 0, sizeof (i));
|
||||
}
|
||||
static struct xdnd_get_drop_info i;
|
||||
if (xevent->xclient.message_type == dnd.XdndEnter)
|
||||
{
|
||||
/* setup user structure */
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.actionlist = actionlist;
|
||||
i.typelist = typelist;
|
||||
dnd.user_hook1 = &i;
|
||||
|
||||
/* setup methods */
|
||||
/* setup methods */
|
||||
dnd.widget_insert_drop = widget_insert_drop;
|
||||
dnd.widget_apply_position = widget_apply_position;
|
||||
|
||||
/* main loop */
|
||||
for (;;) {
|
||||
xdnd_handle_drop_events (&dnd, xevent);
|
||||
if (dnd.stage == XDND_DROP_STAGE_IDLE)
|
||||
break;
|
||||
XNextEvent (dnd.display, xevent);
|
||||
}
|
||||
|
||||
/* return results */
|
||||
if (i.drop_data) {
|
||||
*length = i.drop_data_length;
|
||||
*data = i.drop_data;
|
||||
action = i.return_action;
|
||||
*type = i.return_type;
|
||||
*x = i.x;
|
||||
*y = i.y;
|
||||
}
|
||||
event_type = GHOST_kEventDraggingEntered;
|
||||
handle_enter(&dnd, xevent);
|
||||
}
|
||||
return action;
|
||||
else if (xevent->xclient.message_type == dnd.XdndPosition)
|
||||
{
|
||||
event_type = GHOST_kEventDraggingUpdated;
|
||||
handle_update(&dnd, xevent);
|
||||
}
|
||||
else if (xevent->xclient.message_type == dnd.XdndDrop)
|
||||
{
|
||||
event_type = GHOST_kEventDraggingDropDone;
|
||||
handle_drop(&dnd, xevent);
|
||||
}
|
||||
else if (xevent->xclient.message_type == dnd.XdndLeave)
|
||||
{
|
||||
event_type = GHOST_kEventDraggingExited;
|
||||
handle_exit(&dnd, xevent);
|
||||
}
|
||||
/* return results */
|
||||
*length = i.drop_data_length;
|
||||
i.drop_data_length=0;
|
||||
*data = i.drop_data;
|
||||
/* data wil be free outside */
|
||||
i.drop_data=NULL;
|
||||
*type = i.return_type;
|
||||
*x = i.x;
|
||||
*y = i.y;
|
||||
return event_type;
|
||||
}
|
||||
|
||||
|
||||
|
4
extern/xdnd/xdnd.h
vendored
4
extern/xdnd/xdnd.h
vendored
@ -16,7 +16,7 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "../../intern/ghost/GHOST_Types.h"
|
||||
#ifndef _X_DND_H
|
||||
#define _X_DND_H
|
||||
|
||||
@ -208,7 +208,7 @@ Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist);
|
||||
libraries main event loop and be called if the event type is
|
||||
ClientMessage or SelectionNotify */
|
||||
int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent);
|
||||
Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
|
||||
GHOST_TEventType xdnd_handle_event (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
|
||||
unsigned char **data, int *length, Atom * type, int *x, int *y);
|
||||
|
||||
|
||||
|
@ -81,12 +81,13 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object,
|
||||
DWORD *pdw_effect)
|
||||
{
|
||||
/* We accept all drop by default. */
|
||||
void *data = getGhostData(p_data_object);
|
||||
m_window->setAcceptDragOperation(true);
|
||||
*pdw_effect = DROPEFFECT_NONE;
|
||||
|
||||
m_draggedObjectType = getGhostType(p_data_object);
|
||||
m_system->pushDragDropEvent(
|
||||
GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
|
||||
GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, data);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -202,24 +202,25 @@ bool GHOST_DropTargetX11::GHOST_HandleClientMessage(XEvent *event)
|
||||
uchar *dropBuffer;
|
||||
int dropBufferSize, dropX, dropY;
|
||||
|
||||
if (xdnd_get_drop(m_system->getXDisplay(),
|
||||
event,
|
||||
m_dndTypes,
|
||||
m_dndActions,
|
||||
&dropBuffer,
|
||||
&dropBufferSize,
|
||||
&dropType,
|
||||
&dropX,
|
||||
&dropY)) {
|
||||
void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
|
||||
GHOST_TEventType event_type = xdnd_handle_event(m_system->getXDisplay(),
|
||||
event,
|
||||
m_dndTypes,
|
||||
m_dndActions,
|
||||
&dropBuffer,
|
||||
&dropBufferSize,
|
||||
&dropType,
|
||||
&dropX,
|
||||
&dropY);
|
||||
if (event_type > 0) {
|
||||
|
||||
if (data) {
|
||||
m_system->pushDragDropEvent(
|
||||
GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
|
||||
void *data = nullptr;
|
||||
if (dropBufferSize > 0) {
|
||||
data = getGhostData(dropType, dropBuffer, dropBufferSize);
|
||||
}
|
||||
m_system->pushDragDropEvent(event_type, m_draggedObjectType, m_window, dropX, dropY, data);
|
||||
if (dropBufferSize > 0) {
|
||||
free(dropBuffer);
|
||||
}
|
||||
|
||||
free(dropBuffer);
|
||||
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
|
||||
|
||||
return true;
|
||||
|
@ -70,7 +70,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path)
|
||||
if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
|
||||
WM_drag_data_free(but->dragtype, but->dragpoin);
|
||||
}
|
||||
but->dragpoin = WM_drag_create_path_data(path);
|
||||
but->dragpoin = WM_drag_create_path_data(&path, 1);
|
||||
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
io_utils.c
|
||||
io_alembic.c
|
||||
io_cache.c
|
||||
io_collada.c
|
||||
@ -38,6 +39,7 @@ set(SRC
|
||||
io_stl_ops.c
|
||||
io_usd.c
|
||||
|
||||
io_utils.h
|
||||
io_alembic.h
|
||||
io_cache.h
|
||||
io_collada.h
|
||||
|
@ -38,6 +38,7 @@
|
||||
# include "IO_path_util_types.h"
|
||||
# include "IO_wavefront_obj.h"
|
||||
# include "io_obj.h"
|
||||
# include "io_utils.h"
|
||||
|
||||
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
|
||||
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
|
||||
@ -370,12 +371,6 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int wm_obj_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
struct OBJImportParams import_params;
|
||||
@ -457,6 +452,7 @@ static void wm_obj_import_draw(bContext *C, wmOperator *op)
|
||||
PointerRNA ptr;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
|
||||
files_drop_info_draw(C, op, ICON_FILE_3D);
|
||||
ui_obj_import_settings(op->layout, &ptr);
|
||||
}
|
||||
|
||||
@ -467,9 +463,9 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
|
||||
ot->name = "Import Wavefront OBJ";
|
||||
ot->description = "Load a Wavefront OBJ scene";
|
||||
ot->idname = "WM_OT_obj_import";
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = wm_obj_import_invoke;
|
||||
ot->invoke = wm_io_import_invoke;
|
||||
ot->exec = wm_obj_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_obj_import_draw;
|
||||
@ -482,6 +478,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
|
||||
WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
skip_save_import_paths_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES);
|
||||
RNA_def_float(
|
||||
ot->srna,
|
||||
"global_scale",
|
||||
@ -533,4 +530,22 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
bool obj_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
|
||||
{
|
||||
if (drag->type == WM_DRAG_PATH) {
|
||||
const eFileSel_File_Types file_type = WM_drag_get_path_file_type(drag);
|
||||
if (file_type == FILE_TYPE_OBJECT_IO &&
|
||||
BLI_path_extension_check(WM_drag_get_paths(drag)[0], ".obj")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WM_obj_dropbox_add()
|
||||
{
|
||||
ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
|
||||
WM_dropbox_add(lb, "WM_OT_obj_import", obj_file_drop_poll, files_drop_copy, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif /* WITH_IO_WAVEFRONT_OBJ */
|
||||
|
@ -10,3 +10,4 @@ struct wmOperatorType;
|
||||
|
||||
void WM_OT_obj_export(struct wmOperatorType *ot);
|
||||
void WM_OT_obj_import(struct wmOperatorType *ot);
|
||||
void WM_obj_dropbox_add();
|
||||
|
@ -33,18 +33,22 @@ void ED_operatortypes_io(void)
|
||||
/* Collada operators: */
|
||||
WM_operatortype_append(WM_OT_collada_export);
|
||||
WM_operatortype_append(WM_OT_collada_import);
|
||||
// WM_collada_dropbox_add();
|
||||
#endif
|
||||
#ifdef WITH_ALEMBIC
|
||||
WM_operatortype_append(WM_OT_alembic_import);
|
||||
WM_operatortype_append(WM_OT_alembic_export);
|
||||
// WM_alembic_dropbox_add();
|
||||
#endif
|
||||
#ifdef WITH_USD
|
||||
WM_operatortype_append(WM_OT_usd_import);
|
||||
WM_operatortype_append(WM_OT_usd_export);
|
||||
// WM_usd_dropbox_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_GPENCIL
|
||||
WM_operatortype_append(WM_OT_gpencil_import_svg);
|
||||
// WM_gpencil_dropbox_add();
|
||||
# ifdef WITH_PUGIXML
|
||||
WM_operatortype_append(WM_OT_gpencil_export_svg);
|
||||
# endif
|
||||
@ -63,14 +67,17 @@ void ED_operatortypes_io(void)
|
||||
#ifdef WITH_IO_WAVEFRONT_OBJ
|
||||
WM_operatortype_append(WM_OT_obj_export);
|
||||
WM_operatortype_append(WM_OT_obj_import);
|
||||
WM_obj_dropbox_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_PLY
|
||||
WM_operatortype_append(WM_OT_ply_export);
|
||||
WM_operatortype_append(WM_OT_ply_import);
|
||||
// WM_ply_dropbox_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_STL
|
||||
WM_operatortype_append(WM_OT_stl_import);
|
||||
// WM_stl_dropbox_add();
|
||||
#endif
|
||||
}
|
||||
|
106
source/blender/editors/io/io_utils.c
Normal file
106
source/blender/editors/io/io_utils.c
Normal file
@ -0,0 +1,106 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \
|
||||
defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD)
|
||||
|
||||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BKE_context.h"
|
||||
|
||||
# include "BLI_path_util.h"
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_utildefines.h"
|
||||
# include "BLT_translation.h"
|
||||
|
||||
# include "ED_fileselect.h"
|
||||
|
||||
# include "RNA_access.h"
|
||||
# include "RNA_define.h"
|
||||
|
||||
# include "UI_interface.h"
|
||||
|
||||
# include "WM_api.h"
|
||||
# include "io_utils.h"
|
||||
|
||||
int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
if (filepath[0]) {
|
||||
return WM_operator_props_dialog_popup(C, op, 300);
|
||||
}
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void skip_save_import_paths_props(wmOperatorType *ot, const eFileSel_Flag flag)
|
||||
{
|
||||
if (flag & WM_FILESEL_FILEPATH) {
|
||||
RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "filepath"), PROP_SKIP_SAVE);
|
||||
}
|
||||
if (flag & WM_FILESEL_FILENAME) {
|
||||
RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "filename"), PROP_SKIP_SAVE);
|
||||
}
|
||||
if (flag & WM_FILESEL_DIRECTORY) {
|
||||
RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "directory"), PROP_SKIP_SAVE);
|
||||
}
|
||||
if (flag & WM_FILESEL_FILES) {
|
||||
RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "files"), PROP_SKIP_SAVE);
|
||||
}
|
||||
if (flag & WM_FILESEL_RELPATH) {
|
||||
RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "relative_path"),
|
||||
PROP_SKIP_SAVE);
|
||||
}
|
||||
}
|
||||
|
||||
void files_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
const char **paths = WM_drag_get_paths(drag);
|
||||
RNA_string_set(drop->ptr, "filepath", paths[0]);
|
||||
|
||||
char dir[FILE_MAX], file[FILE_MAX];
|
||||
BLI_split_dirfile(paths[0], dir, file, sizeof(dir), sizeof(file));
|
||||
|
||||
RNA_string_set(drop->ptr, "directory", dir);
|
||||
RNA_collection_clear(drop->ptr, "files");
|
||||
|
||||
const int path_count = WM_drag_get_path_count(drag);
|
||||
for (int i = 0; i < path_count; i++) {
|
||||
BLI_split_dirfile(paths[i], dir, file, sizeof(dir), sizeof(file));
|
||||
PointerRNA itemptr;
|
||||
RNA_collection_add(drop->ptr, "files", &itemptr);
|
||||
RNA_string_set(&itemptr, "name", file);
|
||||
}
|
||||
}
|
||||
|
||||
void file_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]);
|
||||
}
|
||||
|
||||
void file_drop_info_draw(bContext *C, wmOperator *op, int icon)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
if (area->spacetype != SPACE_FILE) {
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
uiLayout *box = uiLayoutBox(op->layout);
|
||||
uiItemL(box, filepath, icon);
|
||||
}
|
||||
}
|
||||
|
||||
void files_drop_info_draw(bContext *C, wmOperator *op, int icon)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
if (area->spacetype != SPACE_FILE) {
|
||||
char label[FILE_MAX] = "Multiple files selected.";
|
||||
|
||||
if (RNA_collection_length(op->ptr, "files") == 1) {
|
||||
RNA_string_get(op->ptr, "filepath", label);
|
||||
}
|
||||
uiLayout *box = uiLayoutBox(op->layout);
|
||||
uiItemL(box, label, icon);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
27
source/blender/editors/io/io_utils.h
Normal file
27
source/blender/editors/io/io_utils.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \
|
||||
defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD)
|
||||
|
||||
# include "WM_types.h"
|
||||
|
||||
struct wmOperator;
|
||||
struct wmOperatorType;
|
||||
struct wmDrag;
|
||||
struct wmDropBox;
|
||||
|
||||
int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event));
|
||||
|
||||
void skip_save_import_paths_props(wmOperatorType *ot, const eFileSel_Flag flag);
|
||||
|
||||
void file_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop);
|
||||
// Function that copies file directories for operators that support importing multiple files
|
||||
void files_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop);
|
||||
|
||||
void file_drop_info_draw(bContext *C, wmOperator *op, int icon);
|
||||
// Function that summarizes file information for operators that support importing multiple files
|
||||
void files_drop_info_draw(bContext *C, wmOperator *op, int icon);
|
||||
|
||||
#endif
|
@ -4564,7 +4564,7 @@ static void screen_animation_region_tag_redraw(
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
|
||||
//#define PROFILE_AUDIO_SYNCH
|
||||
// #define PROFILE_AUDIO_SYNCH
|
||||
|
||||
static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
||||
{
|
||||
@ -5756,7 +5756,7 @@ static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEven
|
||||
static void blend_file_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
/* copy drag path to properties */
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]);
|
||||
}
|
||||
|
||||
void ED_keymap_screen(wmKeyConfig *keyconf)
|
||||
|
@ -527,7 +527,7 @@ static void clip_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
PointerRNA itemptr;
|
||||
char dir[FILE_MAX], file[FILE_MAX];
|
||||
|
||||
BLI_split_dirfile(WM_drag_get_path(drag), dir, file, sizeof(dir), sizeof(file));
|
||||
BLI_split_dirfile(WM_drag_get_paths(drag)[0], dir, file, sizeof(dir), sizeof(file));
|
||||
|
||||
RNA_string_set(drop->ptr, "directory", dir);
|
||||
|
||||
|
@ -172,7 +172,7 @@ static bool path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU
|
||||
static void path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
char pathname[FILE_MAX + 2];
|
||||
BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", WM_drag_get_path(drag));
|
||||
BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", WM_drag_get_paths(drag)[0]);
|
||||
RNA_string_set(drop->ptr, "text", pathname);
|
||||
}
|
||||
|
||||
|
@ -783,7 +783,7 @@ static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(
|
||||
|
||||
static void filepath_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]);
|
||||
}
|
||||
|
||||
/* region dropbox definition */
|
||||
|
@ -268,7 +268,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
|
||||
static void image_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
/* copy drag path to properties */
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]);
|
||||
}
|
||||
|
||||
/* area+region dropbox definition */
|
||||
|
@ -711,7 +711,7 @@ static void node_id_path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *dr
|
||||
return;
|
||||
}
|
||||
|
||||
const char *path = WM_drag_get_path(drag);
|
||||
const char *path = WM_drag_get_paths(drag)[0];
|
||||
if (path) {
|
||||
RNA_string_set(drop->ptr, "filepath", path);
|
||||
RNA_struct_property_unset(drop->ptr, "name");
|
||||
|
@ -247,7 +247,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
|
||||
return;
|
||||
}
|
||||
|
||||
const char *path = WM_drag_get_path(drag);
|
||||
const char *path = WM_drag_get_paths(drag)[0];
|
||||
/* Path dropped. */
|
||||
if (path) {
|
||||
if (RNA_struct_find_property(drop->ptr, "filepath")) {
|
||||
@ -335,7 +335,7 @@ static void get_drag_path(wmDrag *drag, char r_path[FILE_MAX])
|
||||
BLI_path_abs(r_path, BKE_main_blendfile_path_from_global());
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(r_path, WM_drag_get_path(drag), FILE_MAX);
|
||||
BLI_strncpy(r_path, WM_drag_get_paths(drag)[0], FILE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,7 @@ static bool text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU
|
||||
static void text_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
/* copy drag path to properties */
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag));
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]);
|
||||
}
|
||||
|
||||
static bool text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
|
||||
|
@ -903,7 +903,7 @@ static void view3d_id_path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *
|
||||
RNA_struct_property_unset(drop->ptr, "filepath");
|
||||
return;
|
||||
}
|
||||
const char *path = WM_drag_get_path(drag);
|
||||
const char *path = WM_drag_get_paths(drag)[0];
|
||||
if (path) {
|
||||
RNA_string_set(drop->ptr, "filepath", path);
|
||||
RNA_struct_property_unset(drop->ptr, "image");
|
||||
|
@ -1445,13 +1445,15 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag);
|
||||
|
||||
const char *WM_drag_get_item_name(struct wmDrag *drag);
|
||||
|
||||
/* Path drag and drop. */
|
||||
/* Paths drag and drop. */
|
||||
/**
|
||||
* \param path: The path to drag. Value will be copied into the drag data so the passed string may
|
||||
* be destructed.
|
||||
* \param paths: The paths to drag. Value will be copied into the drag data so the passed strings
|
||||
* may be destructed. Only paths that share the same extension of the first file will be copied.
|
||||
* \param path_count: the number of paths in #paths
|
||||
*/
|
||||
wmDragPath *WM_drag_create_path_data(const char *path);
|
||||
const char *WM_drag_get_path(const wmDrag *drag);
|
||||
wmDragPath *WM_drag_create_path_data(const char **paths, int path_count);
|
||||
const char **WM_drag_get_paths(const wmDrag *drag);
|
||||
const int WM_drag_get_path_count(const wmDrag *drag);
|
||||
/**
|
||||
* Note that even though the enum return type uses bit-flags, this should never have multiple
|
||||
* type-bits set, so `ELEM()` like comparison is possible.
|
||||
|
@ -1133,7 +1133,9 @@ typedef struct wmDragAssetListItem {
|
||||
} wmDragAssetListItem;
|
||||
|
||||
typedef struct wmDragPath {
|
||||
char *path;
|
||||
char **paths;
|
||||
char *tooltip;
|
||||
int path_count;
|
||||
/* Note that even though the enum type uses bit-flags, this should never have multiple type-bits
|
||||
* set, so `ELEM()` like comparison is possible. */
|
||||
int file_type; /* eFileSel_File_Types */
|
||||
|
@ -750,29 +750,70 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag)
|
||||
return &drag->asset_items;
|
||||
}
|
||||
|
||||
wmDragPath *WM_drag_create_path_data(const char *path)
|
||||
wmDragPath *WM_drag_create_path_data(const char **paths, int path_count)
|
||||
{
|
||||
wmDragPath *path_data = MEM_new<wmDragPath>("wmDragPath");
|
||||
path_data->path = BLI_strdup(path);
|
||||
path_data->file_type = ED_path_extension_type(path);
|
||||
|
||||
const char *ext = BLI_path_extension(paths[0]);
|
||||
|
||||
int valid_path_count = 1;
|
||||
for (int i = 1; i < path_count; i++) {
|
||||
if ((ext == nullptr && BLI_path_extension(paths[i]) == nullptr) ||
|
||||
(ext != nullptr && BLI_path_extension_check(paths[i], ext))) {
|
||||
valid_path_count++;
|
||||
}
|
||||
}
|
||||
path_data->paths = (char **)MEM_mallocN(valid_path_count * sizeof(char *), "paths");
|
||||
|
||||
int path_index = 0;
|
||||
for (int i = 0; i < path_count; i++) {
|
||||
if ((ext == nullptr && BLI_path_extension(paths[i]) == nullptr) ||
|
||||
(ext != nullptr && BLI_path_extension_check(paths[i], ext))) {
|
||||
path_data->paths[path_index] = BLI_strdup(paths[i]);
|
||||
path_index++;
|
||||
}
|
||||
}
|
||||
|
||||
path_data->file_type = ED_path_extension_type(paths[0]);
|
||||
path_data->path_count = valid_path_count;
|
||||
if (path_count == 1) {
|
||||
path_data->tooltip = BLI_strdup(paths[0]);
|
||||
}
|
||||
else {
|
||||
const char *tooltip = TIP_("Dragging %d %s files.");
|
||||
path_data->tooltip = BLI_sprintfN(tooltip, valid_path_count, ext);
|
||||
}
|
||||
return path_data;
|
||||
}
|
||||
|
||||
static void wm_drag_free_path_data(wmDragPath **path_data)
|
||||
{
|
||||
MEM_freeN((*path_data)->path);
|
||||
for (int i = 0; i < (*path_data)->path_count; i++) {
|
||||
MEM_freeN((*path_data)->paths[i]);
|
||||
}
|
||||
MEM_freeN((*path_data)->paths);
|
||||
MEM_freeN((*path_data)->tooltip);
|
||||
MEM_delete(*path_data);
|
||||
*path_data = nullptr;
|
||||
}
|
||||
|
||||
const char *WM_drag_get_path(const wmDrag *drag)
|
||||
const char **WM_drag_get_paths(const wmDrag *drag)
|
||||
{
|
||||
if (drag->type != WM_DRAG_PATH) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
|
||||
return path_data->path;
|
||||
return const_cast<const char **>(path_data->paths);
|
||||
}
|
||||
const int WM_drag_get_path_count(const wmDrag *drag)
|
||||
{
|
||||
if (drag->type != WM_DRAG_PATH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const wmDragPath *path_data = static_cast<const wmDragPath *>(drag->poin);
|
||||
return path_data->path_count;
|
||||
}
|
||||
|
||||
int WM_drag_get_path_file_type(const wmDrag *drag)
|
||||
@ -836,7 +877,7 @@ const char *WM_drag_get_item_name(wmDrag *drag)
|
||||
}
|
||||
case WM_DRAG_PATH: {
|
||||
const wmDragPath *path_drag_data = static_cast<const wmDragPath *>(drag->poin);
|
||||
return path_drag_data->path;
|
||||
return path_drag_data->tooltip;
|
||||
}
|
||||
case WM_DRAG_NAME:
|
||||
return static_cast<const char *>(drag->poin);
|
||||
|
@ -1192,6 +1192,39 @@ void wm_window_reset_drawable(void)
|
||||
}
|
||||
}
|
||||
|
||||
void update_mouse_position_from_draganddrop(wmWindowManager *wm,
|
||||
wmWindow *win,
|
||||
wmEvent *event,
|
||||
GHOST_TEventDragnDropData *ddd)
|
||||
{
|
||||
/* Ensure the event state matches modifiers (window was inactive). */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
/* Entering window, update mouse position (without sending an event). */
|
||||
wm_window_update_eventstate(win);
|
||||
|
||||
wm_event_init_from_window(win, event); /* copy last state, like mouse coords */
|
||||
|
||||
/* activate region */
|
||||
event->type = MOUSEMOVE;
|
||||
event->val = KM_NOTHING;
|
||||
copy_v2_v2_int(event->prev_xy, event->xy);
|
||||
|
||||
wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y);
|
||||
event->xy[0] = ddd->x;
|
||||
event->xy[1] = ddd->y;
|
||||
|
||||
/* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
|
||||
* Write this into the event state. */
|
||||
copy_v2_v2_int(win->eventstate->xy, event->xy);
|
||||
|
||||
event->flag = 0;
|
||||
|
||||
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
|
||||
wm->winactive = win;
|
||||
win->active = 1;
|
||||
wm_event_add(win, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by ghost, here we handle events for windows themselves or send to event system.
|
||||
*
|
||||
@ -1439,37 +1472,40 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GHOST_kEventDraggingEntered: {
|
||||
WM_drag_free_list(&wm->drags);
|
||||
wm_drags_exit(wm, win);
|
||||
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
|
||||
|
||||
wmEvent event;
|
||||
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
|
||||
|
||||
/* add drag data to wm for paths: */
|
||||
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
|
||||
GHOST_TStringArray *stra = ddd->data;
|
||||
|
||||
if (stra->count > 0) {
|
||||
/* try to get icon type from extension */
|
||||
int icon = ED_file_extension_icon((char *)stra->strings[0]);
|
||||
wmDragPath *path_data = WM_drag_create_path_data((char **)stra->strings, stra->count);
|
||||
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
|
||||
/* void poin should point to string, it makes a copy */
|
||||
break; /* only one drop element supported now */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GHOST_kEventDraggingUpdated: {
|
||||
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
|
||||
wmEvent event;
|
||||
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
|
||||
break;
|
||||
}
|
||||
case GHOST_kEventDraggingDropDone: {
|
||||
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
|
||||
|
||||
/* Ensure the event state matches modifiers (window was inactive). */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
/* Entering window, update mouse position (without sending an event). */
|
||||
wm_window_update_eventstate(win);
|
||||
|
||||
wmEvent event;
|
||||
wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */
|
||||
|
||||
/* activate region */
|
||||
event.type = MOUSEMOVE;
|
||||
event.val = KM_NOTHING;
|
||||
copy_v2_v2_int(event.prev_xy, event.xy);
|
||||
|
||||
wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y);
|
||||
event.xy[0] = ddd->x;
|
||||
event.xy[1] = ddd->y;
|
||||
|
||||
/* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
|
||||
* Write this into the event state. */
|
||||
copy_v2_v2_int(win->eventstate->xy, event.xy);
|
||||
|
||||
event.flag = 0;
|
||||
|
||||
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
|
||||
wm->winactive = win;
|
||||
win->active = 1;
|
||||
|
||||
wm_event_add(win, &event);
|
||||
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
|
||||
|
||||
/* make blender drop event with custom data pointing to wm drags */
|
||||
event.type = EVT_DROP;
|
||||
@ -1479,27 +1515,29 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
||||
event.customdata_free = true;
|
||||
|
||||
wm_event_add(win, &event);
|
||||
|
||||
// printf("Drop detected\n");
|
||||
|
||||
/* add drag data to wm for paths: */
|
||||
|
||||
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
|
||||
if (wm->drags.first != NULL && ddd->dataType == GHOST_kDragnDropTypeFilenames) {
|
||||
GHOST_TStringArray *stra = ddd->data;
|
||||
|
||||
for (int a = 0; a < stra->count; a++) {
|
||||
printf("drop file %s\n", stra->strings[a]);
|
||||
if (stra->count > 0) {
|
||||
/* try to get icon type from extension */
|
||||
int icon = ED_file_extension_icon((char *)stra->strings[a]);
|
||||
wmDragPath *path_data = WM_drag_create_path_data((char *)stra->strings[a]);
|
||||
int icon = ED_file_extension_icon((char *)stra->strings[0]);
|
||||
wmDragPath *path_data = WM_drag_create_path_data((char **)stra->strings, stra->count);
|
||||
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
|
||||
/* void poin should point to string, it makes a copy */
|
||||
break; /* only one drop element supported now */
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GHOST_kEventDraggingExited: {
|
||||
WM_drag_free_list(&wm->drags);
|
||||
wm_drags_exit(wm, win);
|
||||
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
|
||||
wmEvent event;
|
||||
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
|
||||
break;
|
||||
}
|
||||
|
||||
case GHOST_kEventNativeResolutionChange: {
|
||||
/* Only update if the actual pixel size changes. */
|
||||
float prev_pixelsize = U.pixelsize;
|
||||
|
Loading…
Reference in New Issue
Block a user