Kaynağa Gözat

[hldx] Implement Drag&Drop api (#630)

Pavel Alexandrov 1 yıl önce
ebeveyn
işleme
2f8a7031dd

+ 4 - 0
libs/directx/dx/Event.hx

@@ -14,6 +14,7 @@ package dx;
 	public var keyRepeat : Bool;
 	public var controller : Int;
 	public var value : Int;
+	public var dropFile: hl.Bytes;
 	public function new() {
 	}
 }
@@ -29,6 +30,9 @@ enum abstract EventType(Int) {
 	var KeyDown		= 7;
 	var KeyUp		= 8;
 	var TextInput	= 9;
+	var DropStart = 10;
+	var DropFile = 11;
+	var DropEnd = 12;
 }
 
 enum abstract WindowStateChange(Int) {

+ 10 - 0
libs/directx/dx/Window.hx

@@ -50,6 +50,7 @@ class Window {
 	public var displaySetting : DisplaySetting;
 	public var selectedMonitor : MonitorHandle;
 	public var vsync : Bool;
+	public var dragAndDropEnabled(default, set) : Bool;
 
 	public function new( title : String, width : Int, height : Int, x : Int = CW_USEDEFAULT, y : Int = CW_USEDEFAULT, windowFlags : Int = RESIZABLE ) {
 		win = winCreateEx(x, y, width, height, windowFlags);
@@ -243,6 +244,11 @@ class Window {
 		winSetOpacity(win, v);
 		return v;
 	}
+	
+	function set_dragAndDropEnabled(v) {
+		winSetDragAcceptFiles(win, v);
+		return dragAndDropEnabled = v;
+	}
 
 	@:hlNative("?directx", "win_get_display_settings")
 	static function winGetDisplaySettings(monitor : hl.Bytes) : hl.NativeArray<Dynamic> {
@@ -354,5 +360,9 @@ class Window {
 	static function winGetRelativeMouseMode() : Bool { 
 		return false;
 	}
+	
+	@:hlNative("?directx", "win_set_drag_accept_files")
+	static function winSetDragAcceptFiles( win : WinPtr, enable: Bool ) : Void {
+	}
 
 }

+ 1 - 1
libs/directx/haxelib.json

@@ -4,7 +4,7 @@
 	"license" : "BSD",
 	"contributors" : ["ncannasse"],
 	"description" : "DirectX support for Haxe/HL.",
-	"version" : "1.13.0",
+	"version" : "1.14.0",
 	"releasenote" : "",
 	"dependencies": { "hlopenal" : "" }
 }

+ 63 - 1
libs/directx/window.c

@@ -13,7 +13,10 @@ typedef enum {
 	WindowState	= 6,
 	KeyDown		= 7,
 	KeyUp		= 8,
-	TextInput	= 9
+	TextInput	= 9,
+	DropStart = 10,
+	DropFile = 11,
+	DropEnd = 12,
 } EventType;
 
 typedef enum {
@@ -52,6 +55,7 @@ typedef struct {
 	bool keyRepeat;
 	int controller;
 	int value;
+	vbyte* dropFile;
 } dx_event;
 
 typedef struct {
@@ -459,6 +463,47 @@ static LRESULT CALLBACK WndProc( HWND wnd, UINT umsg, WPARAM wparam, LPARAM lpar
 			return TRUE;
 		}
 		break;
+	case WM_DROPFILES:
+	{
+		HDROP drop = (HDROP)wparam;
+		UINT count = DragQueryFileW(drop, 0xFFFFFFFF, NULL, 0);
+
+		POINT dragPoint;
+		if ( !DragQueryPoint(drop, &dragPoint) ) {
+			dragPoint.x = 0L;
+			dragPoint.y = 0L;
+		}
+
+		e = addEvent(wnd, DropStart);
+		e->value = count;
+		e->mouseX = (int)dragPoint.x;
+		e->mouseY = (int)dragPoint.y;
+
+		for ( UINT i = 0; i < count; i++ ) {
+			UINT size = DragQueryFileW(drop, i, NULL, 0) + 1; // + zero terminator
+			// We have to make a temporary unmanaged buffer copy due to async nature of event being
+			// processed and collected by Haxe event loop, and using GC-allocated buffer risks
+			// resulting in garbage data if GC is ran at any point inbetween due to freed buffer.
+			// As a consequence, this event requires checks during fetching of the next event
+			// (and window destruction) in order to ensure Haxe side gets proper buffer without memory leaks.
+			vbyte* buffer = malloc(size * sizeof(WCHAR));
+			if ( DragQueryFileW(drop, i, (LPWSTR)buffer, size) ) {
+				e = addEvent(wnd, DropFile);
+				e->value = size * sizeof(WCHAR);
+				e->dropFile = buffer;
+				e->mouseX = (int)dragPoint.x;
+				e->mouseY = (int)dragPoint.y;
+			} else {
+				free(buffer);
+			}
+		}
+		e = addEvent(wnd, DropEnd);
+		e->value = count;
+		e->mouseX = (int)dragPoint.x;
+		e->mouseY = (int)dragPoint.y;
+		DragFinish(drop);
+		break;
+	}
 	case WM_CLOSE:
 		addEvent(wnd, Quit);
 		return 0;
@@ -704,6 +749,11 @@ HL_PRIM void HL_NAME(win_destroy)(dx_window *win) {
 		ClipCursor(NULL);
 	}
 	dx_events *buf = get_events(win);
+	// See WM_DROPFILES comment regarding GC
+	for ( int i = buf->next_event; i < buf->event_count; i++ ) {
+		if ( buf->events[i].dropFile != NULL )
+			free(buf->events[i].dropFile);
+	}
 	free(buf);
 	SetWindowLongPtr(win,GWLP_USERDATA,0);
 	DestroyWindow(win);
@@ -722,6 +772,13 @@ HL_PRIM bool HL_NAME(win_get_next_event)( dx_window *win, dx_event *e ) {
 	}
 	save = e->t;
 	memcpy(e,&buf->events[buf->next_event++],sizeof(dx_event));
+	if ( e->type == DropFile ) {
+		// See WM_DROPFILES comment regarding GC
+		vbyte* unmanaged = e->dropFile;
+		e->dropFile = hl_copy_bytes(unmanaged, e->value);
+		free(unmanaged);
+		buf->events[buf->next_event - 1].dropFile = NULL;
+	}
 	e->t = save;
 	return true;
 }
@@ -754,6 +811,10 @@ HL_PRIM bool HL_NAME(win_get_relative_mouse_mode)() {
 	return relative_mouse;
 }
 
+HL_PRIM void HL_NAME(win_set_drag_accept_files)( dx_window* wnd, bool enabled ) {
+	DragAcceptFiles(wnd, enabled);
+}
+
 HL_PRIM int HL_NAME(get_screen_width)() {
 	return GetSystemMetrics(SM_CXSCREEN);
 }
@@ -875,6 +936,7 @@ DEFINE_PRIM(_BOOL, set_cursor_pos, _I32 _I32);
 DEFINE_PRIM(_BOOL, win_set_cursor_pos, TWIN _I32 _I32);
 DEFINE_PRIM(_BOOL, win_set_relative_mouse_mode, TWIN _BOOL);
 DEFINE_PRIM(_BOOL, win_get_relative_mouse_mode, _NO_ARG);
+DEFINE_PRIM(_VOID, win_set_drag_accept_files, TWIN _BOOL);
 DEFINE_PRIM(_ARR, win_get_display_settings, _BYTES);
 DEFINE_PRIM(_DYN, win_get_current_display_setting, _BYTES _BOOL);
 DEFINE_PRIM(_I32, win_change_display_setting, _BYTES _DYN);

+ 1 - 1
libs/sdl/haxelib.json

@@ -4,7 +4,7 @@
 	"license" : "BSD",
 	"contributors" : ["ncannasse"],
 	"description" : "SDL/GL support for Haxe/HL.",
-	"version" : "1.13.0",
+	"version" : "1.14.0",
 	"releasenote" : "",
 	"dependencies": { "hlopenal" : "" }
 }