Pavel Alexandrov преди 1 година
родител
ревизия
6ccc6ad92d
променени са 4 файла, в които са добавени 189 реда и са изтрити 0 реда
  1. 68 0
      hxd/DropFileEvent.hx
  2. 57 0
      hxd/Window.hl.hx
  3. 12 0
      hxd/Window.hx
  4. 52 0
      hxd/Window.js.hx

+ 68 - 0
hxd/DropFileEvent.hx

@@ -0,0 +1,68 @@
+package hxd;
+
+import haxe.ds.ReadOnlyArray;
+import haxe.io.Bytes;
+
+/**
+	The information about the dropped file.
+**/
+abstract class DroppedFile {
+	/**
+		The dropped file name/path.
+	**/
+	public var file(default, null) : String;
+	#if js
+	/**
+		The native JS data transfer file.
+	**/
+	public var native(default, null) : js.html.File;
+
+	#end
+
+	public function new( file : String ) {
+		this.file = file;
+	}
+
+
+	/**
+		Retrieve the dropped file contents asynchronously and pass it to `callback`.
+	**/
+	abstract public function getBytes( callback : (data : Bytes) -> Void ) : Void;
+}
+
+/**
+	The drag&drop operation event.
+
+	@see `hxd.Window.addDragAndDropTarget`
+	@see `hxd.Window.removeDragAndDropTarget`
+**/
+class DropFileEvent {
+	/**
+		The list of the files that were dropped.
+
+		Only guaranteed to be populated when `kind == Drop`.
+	**/
+	public var files(default, null): ReadOnlyArray<DroppedFile>;
+	/**
+		The first dropped file. Alias to `files[0]`.
+	**/
+	public var file(get, never): Null<DroppedFile>;
+	/**
+		The X position inside the window at which the file was dropped.
+	**/
+	public var dropX(default, null): Int;
+	/**
+		The Y position inside the window at which the file was dropped.
+	**/
+	public var dropY(default, null): Int;
+	
+	public function new( files : Array<DroppedFile>, dx : Int, dy : Int ) {
+		this.files = files;
+		this.dropX = dx;
+		this.dropY = dy;
+	}
+
+	inline function get_file() return files[0];
+
+}
+

+ 57 - 0
hxd/Window.hl.hx

@@ -30,11 +30,19 @@ typedef DisplaySetting = {
 	framerate : Int
 }
 
+private class NativeDroppedFile extends hxd.DropFileEvent.DroppedFile {
+	public function getBytes( callback : ( data : haxe.io.Bytes ) -> Void ) {
+		haxe.Timer.delay(() -> callback(sys.io.File.getBytes(file)), 1);
+	}
+}
+
 //@:coreApi
 class Window {
 
 	var resizeEvents : List<Void -> Void>;
 	var eventTargets : List<Event -> Void>;
+	var dropTargets : List<DropFileEvent -> Void>;
+	var dropFiles : Array<hxd.DropFileEvent.DroppedFile>;
 
 	public var width(get, never) : Int;
 	public var height(get, never) : Int;
@@ -92,6 +100,7 @@ class Window {
 		this.windowHeight = height;
 		eventTargets = new List();
 		resizeEvents = new List();
+		dropTargets = new List();
 		#if hlsdl
 		var sdlFlags = if (!fixed) sdl.Window.SDL_WINDOW_SHOWN | sdl.Window.SDL_WINDOW_RESIZABLE else sdl.Window.SDL_WINDOW_SHOWN;
 		#if heaps_vulkan
@@ -168,6 +177,32 @@ class Window {
 		for( f in resizeEvents ) f();
 	}
 
+	public function addDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+		if (dropTargets.length == 0) {
+			#if (hlsdl >= version("1.14.0"))
+			sdl.Sdl.setDragAndDropEnabled(true);
+			#elseif (hldx >= version("1.14.0"))
+			window.dragAndDropEnabled = true;
+			#end
+		}
+		dropTargets.push(f);
+	}
+
+	public function removeDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+		for( e in dropTargets )
+			if( Reflect.compareMethods(e, f) ) {
+				dropTargets.remove(f);
+				break;
+			}
+		if ( dropTargets.length == 0 ) {
+			#if (hlsdl >= version("1.14.0"))
+			sdl.Sdl.setDragAndDropEnabled(false);
+			#elseif (hldx >= version("1.14.0"))
+			window.dragAndDropEnabled = false;
+			#end
+		}
+	}
+
 	public function setCursorPos( x : Int, y : Int, emitEvent : Bool = false ) : Void {
 		#if hldx
 		if (mouseMode == Absolute) window.setCursorPosition(x, y);
@@ -439,6 +474,7 @@ class Window {
 			#end
 			eh = new Event(ERelease, e.mouseX, e.mouseY);
 			eh.touchId = e.fingerId;
+		
 		#elseif hldx
 		case KeyDown:
 			eh = new Event(EKeyDown);
@@ -458,6 +494,27 @@ class Window {
 			eh = new Event(ETextInput, mouseX, mouseY);
 			eh.charCode = e.keyCode;
 		#end
+		#if (hlsdl >= version("1.14.0") || hldx >= version("1.14.0"))
+		case DropStart:
+			dropFiles = [];
+		case DropFile:
+			#if hlsdl
+			dropFiles.push(new NativeDroppedFile(@:privateAccess String.fromUTF8(e.dropFile)));
+			#else
+			dropFiles.push(new NativeDroppedFile(@:privateAccess String.fromUCS2(e.dropFile)));
+			#end
+		case DropEnd:
+			var event = new DropFileEvent(
+				dropFiles,
+				#if hldx
+				e.mouseX, e.mouseY
+				#else
+				mouseX, mouseY
+				#end
+			);
+			for ( dt in dropTargets ) dt(event);
+			dropFiles = null;
+		#end
 		case Quit:
 			return onClose();
 		default:

+ 12 - 0
hxd/Window.hx

@@ -92,6 +92,18 @@ class Window {
 	public function resize( width : Int, height : Int ) : Void {
 	}
 
+	/**
+		Add a drag&drop events callback.
+	**/
+	public function addDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+	}
+
+	/**
+		Remove a drag&drop events callback.
+	**/
+	public function removeDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+	}
+
 	@:deprecated("Use the displayMode property instead")
 	public function setFullScreen( v : Bool ) : Void {
 	}

+ 52 - 0
hxd/Window.js.hx

@@ -10,10 +10,27 @@ enum DisplayMode {
 	FullscreenResize;
 }
 
+private class NativeDroppedFile extends hxd.DropFileEvent.DroppedFile {
+
+	public function new( native : js.html.File ) {
+		super(native.name);
+		this.native = native;
+	}
+
+	public function getBytes( callback : ( data : haxe.io.Bytes ) -> Void ) {
+		var reader = new js.html.FileReader();
+		reader.onload = (_) -> callback(haxe.io.Bytes.ofData(reader.result));
+		reader.onerror = (_) -> callback(null);
+		reader.readAsArrayBuffer(native);
+	}
+
+}
+
 class Window {
 
 	var resizeEvents : List<Void -> Void>;
 	var eventTargets : List<Event -> Void>;
+	var dropTargets : List<DropFileEvent -> Void>;
 
 	public var width(get, never) : Int;
 	public var height(get, never) : Int;
@@ -69,6 +86,7 @@ class Window {
 		var customCanvas = canvas != null;
 		eventTargets = new List();
 		resizeEvents = new List();
+		dropTargets = new List();
 
 		if( !js.Browser.supported ) {
 			canvasPos = { "width":0, "top":0, "left":0, "height":0 };
@@ -221,6 +239,40 @@ class Window {
 	public function resize( width : Int, height : Int ) : Void {
 	}
 
+	public function addDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+		if( dropTargets.length == 0 ) {
+			var element = canvas; // Probably should adhere to `globalEvents`?
+			element.addEventListener("dragover", handleDragAndDropEvent);
+			element.addEventListener("drop", handleDragAndDropEvent);
+		}
+		dropTargets.add(f);
+	}
+
+	public function removeDragAndDropTarget( f : ( event : DropFileEvent ) -> Void ) : Void {
+		for( e in dropTargets )
+			if( Reflect.compareMethods(e, f) ) {
+				dropTargets.remove(f);
+				break;
+			}
+		if( dropTargets.length == 0 ) {
+			var element = canvas; // Probably should adhere to `globalEvents`?
+			element.removeEventListener("dragover", handleDragAndDropEvent);
+			element.removeEventListener("drop", handleDragAndDropEvent);
+		}
+	}
+
+	function handleDragAndDropEvent( e : js.html.DragEvent ) {
+		e.preventDefault();
+		if ( e.type == "dragover" || e.dataTransfer == null || e.dataTransfer.files.length == 0 ) return;
+		var ev = new DropFileEvent([
+				for ( file in e.dataTransfer.files ) new NativeDroppedFile(file)
+			],
+			Math.round((e.clientX - canvasPos.left) * getPixelRatio()),
+			Math.round((e.clientY - canvasPos.top) * getPixelRatio())
+		);
+		for( dt in dropTargets ) dt(ev);
+	}
+
 	@:deprecated("Use the displayMode property instead")
 	public function setFullScreen( v : Bool ) : Void {
 		var doc = js.Browser.document;