Przeglądaj źródła

C# DropTarget (untested)

Marko Pintera 10 lat temu
rodzic
commit
524466d73d

+ 2 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -3,6 +3,7 @@
 #include "BsGUIElementStyle.h"
 #include "BsGUIElementStyle.h"
 
 
 #include "BsGUILabel.h"
 #include "BsGUILabel.h"
+#include "BsGUITexture.h"
 #include "BsGUIButton.h"
 #include "BsGUIButton.h"
 #include "BsGUIInputBox.h"
 #include "BsGUIInputBox.h"
 #include "BsGUIToggle.h"
 #include "BsGUIToggle.h"
@@ -313,6 +314,7 @@ namespace BansheeEngine
 		GUIElementStyle blankStyle;
 		GUIElementStyle blankStyle;
 
 
 		skin->setStyle("Blank", blankStyle);
 		skin->setStyle("Blank", blankStyle);
+		skin->setStyle(GUITexture::getGUITypeName(), blankStyle);
 
 
 		// Label
 		// Label
 		GUIElementStyle labelStyle;
 		GUIElementStyle labelStyle;

+ 0 - 1
BansheeEngine/Source/BsGUILayoutUtility.cpp

@@ -23,7 +23,6 @@ namespace BansheeEngine
 		{
 		{
 			parentArea = calcBounds(parent);
 			parentArea = calcBounds(parent);
 
 
-			// TODO - Implement this properly
 			if (parent->_getType() == GUIElementBase::Type::Panel && (relativeTo == nullptr || relativeTo == parent))
 			if (parent->_getType() == GUIElementBase::Type::Panel && (relativeTo == nullptr || relativeTo == parent))
 			{
 			{
 				parentArea.x = 0;
 				parentArea.x = 0;

+ 71 - 0
MBansheeEditor/DropTarget.cs

@@ -0,0 +1,71 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class DropTarget : ScriptObject
+    {
+        public Action<int, int> OnDrop;
+        public Action<int, int> OnEnter;
+        public Action OnLeave;
+        public Action<int, int> OnDrag;
+
+        public DropTarget(EditorWindow window)
+        {
+            IntPtr nativeWindow = window.GetCachedPtr();;
+            Internal_CreateInstance(this, nativeWindow);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        public Rect2I Bounds
+        {
+            set { Internal_SetBounds(mCachedPtr, value); }
+        }
+
+        public string[] FilePaths
+        {
+            get { return Internal_GetFilePaths(mCachedPtr); }
+        }
+
+        private void InternalDoOnEnter(int x, int y)
+        {
+            if (OnEnter != null)
+                OnEnter(x, y);
+        }
+
+        private void InternalDoOnLeave()
+        {
+            if (OnLeave != null)
+                OnLeave();
+        }
+
+        private void InternalDoOnDrag(int x, int y)
+        {
+            if (OnDrag != null)
+                OnDrag(x, y);
+        }
+
+        private void InternalDoOnDrop(int x, int y)
+        {
+            if (OnDrop != null)
+                OnDrop(x, y);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(DropTarget instance, IntPtr editorWindow);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBounds(IntPtr nativeInstance, Rect2I bounds);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string[] Internal_GetFilePaths(IntPtr nativeInstance);
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -54,6 +54,7 @@
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="DialogBox.cs" />
     <Compile Include="DialogBox.cs" />
     <Compile Include="DragDrop.cs" />
     <Compile Include="DragDrop.cs" />
+    <Compile Include="DropTarget.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorBuiltin.cs" />
     <Compile Include="EditorBuiltin.cs" />
     <Compile Include="EditorSettings.cs" />
     <Compile Include="EditorSettings.cs" />

+ 4 - 0
MBansheeEditor/ProjectWindow.cs

@@ -340,6 +340,8 @@ namespace BansheeEditor
             catchAll.OnClick += OnCatchAllClicked;
             catchAll.OnClick += OnCatchAllClicked;
 
 
             contentUnderlayPanel.AddElement(catchAll);
             contentUnderlayPanel.AddElement(catchAll);
+
+            Debug.Log("REFRESHED " + Time.FrameNumber);
         }
         }
 
 
         private void CreateEntryGUI(GUILayout parentLayout, int tileSize, bool grid, LibraryEntry entry)
         private void CreateEntryGUI(GUILayout parentLayout, int tileSize, bool grid, LibraryEntry entry)
@@ -413,6 +415,8 @@ namespace BansheeEditor
             Select(new List<string> { path });
             Select(new List<string> { path });
 
 
             Selection.resourcePaths = new string[] {path};
             Selection.resourcePaths = new string[] {path};
+
+            Debug.Log("CLICKED " + Time.FrameNumber);
         }
         }
 
 
         private void OnEntryDoubleClicked(string path)
         private void OnEntryDoubleClicked(string path)

+ 58 - 0
SBansheeEditor/Include/BsScriptDropTarget.h

@@ -0,0 +1,58 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsScriptDropTarget.h"
+#include "BsRect2I.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptDropTarget : public ScriptObject <ScriptDropTarget>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "DropTarget")
+
+	private:
+		OSDropTarget* mDropTarget;
+		Rect2I mParentArea;
+		Rect2I mArea;
+		bool mIsDestroyed;
+
+		HEvent mDropTargetEnterConn;
+		HEvent mDropTargetMoveConn;
+		HEvent mDropTargetLeaveConn;
+		HEvent mDropTargetDroppedConn;
+		HEvent mWidgetParentChangedConn;
+		HEvent mWidgetResizedConn;
+
+		ScriptDropTarget(MonoObject* instance, EditorWidgetBase* parent);
+		~ScriptDropTarget();
+
+		void destroy();
+		void setDropTarget(const RenderWindowPtr& parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height);
+		void setBounds(const Rect2I& bounds);
+
+		void widgetParentChanged(EditorWidgetContainer* parent);
+		void widgetResized(UINT32 width, UINT32 height);
+
+		typedef void(__stdcall *OnEnterThunkDef) (MonoObject*, INT32, INT32, MonoException**);
+		typedef void(__stdcall *OnMoveDef) (MonoObject*, INT32, INT32, MonoException**);
+		typedef void(__stdcall *OnLeaveDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnDropThunkDef) (MonoObject*, INT32, INT32, MonoException**);
+
+		static void internal_CreateInstance(MonoObject* instance, ScriptEditorWindow* editorWindow);
+		static void internal_Destroy(ScriptDropTarget* nativeInstance);
+		static void internal_SetBounds(ScriptDropTarget* nativeInstance, Rect2I bounds);
+		static MonoArray* internal_GetFilePaths(ScriptDropTarget* nativeInstance);
+
+		static void dropTargetDragEnter(MonoObject* instance, INT32 x, INT32 y);
+		static void dropTargetDragMove(MonoObject* instance, INT32 x, INT32 y);
+		static void dropTargetDragLeave(MonoObject* instance);
+		static void dropTargetDragDropped(MonoObject* instance, INT32 x, INT32 y);
+
+		static OnEnterThunkDef onEnterThunk;
+		static OnMoveDef onMoveThunk;
+		static OnLeaveDef onLeaveThunk;
+		static OnDropThunkDef onDropThunk;
+	};
+}

+ 2 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -240,6 +240,7 @@
     <ClInclude Include="Include\BsScriptBuildManager.h" />
     <ClInclude Include="Include\BsScriptBuildManager.h" />
     <ClInclude Include="Include\BsScriptCodeEditor.h" />
     <ClInclude Include="Include\BsScriptCodeEditor.h" />
     <ClInclude Include="Include\BsScriptDragDropManager.h" />
     <ClInclude Include="Include\BsScriptDragDropManager.h" />
+    <ClInclude Include="Include\BsScriptDropTarget.h" />
     <ClInclude Include="Include\BsScriptEditorApplication.h" />
     <ClInclude Include="Include\BsScriptEditorApplication.h" />
     <ClInclude Include="Include\BsScriptEditorBuiltin.h" />
     <ClInclude Include="Include\BsScriptEditorBuiltin.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
@@ -283,6 +284,7 @@
     <ClCompile Include="Source\BsGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsGUIGameObjectField.cpp" />
     <ClCompile Include="Source\BsGUIResourceField.cpp" />
     <ClCompile Include="Source\BsGUIResourceField.cpp" />
     <ClCompile Include="Source\BsScriptBrowseDialog.cpp" />
     <ClCompile Include="Source\BsScriptBrowseDialog.cpp" />
+    <ClCompile Include="Source\BsScriptDropTarget.cpp" />
     <ClCompile Include="Source\BsScriptEditorApplication.cpp" />
     <ClCompile Include="Source\BsScriptEditorApplication.cpp" />
     <ClCompile Include="Source\BsScriptEditorBuiltin.cpp" />
     <ClCompile Include="Source\BsScriptEditorBuiltin.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />

+ 6 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -138,6 +138,9 @@
     <ClInclude Include="Include\BsScriptEditorBuiltin.h">
     <ClInclude Include="Include\BsScriptEditorBuiltin.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptDropTarget.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -263,5 +266,8 @@
     <ClCompile Include="Source\BsScriptEditorBuiltin.cpp">
     <ClCompile Include="Source\BsScriptEditorBuiltin.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptDropTarget.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 205 - 0
SBansheeEditor/Source/BsScriptDropTarget.cpp

@@ -0,0 +1,205 @@
+#include "BsScriptDropTarget.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsMonoArray.h"
+#include "BsRTTIType.h"
+#include "BsPlatform.h"
+#include "BsEditorWidget.h"
+#include "BsEditorWindowBase.h"
+#include "BsEditorWidgetContainer.h"
+#include "BsScriptEditorWindow.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptDropTarget::OnEnterThunkDef ScriptDropTarget::onEnterThunk;
+	ScriptDropTarget::OnMoveDef ScriptDropTarget::onMoveThunk;
+	ScriptDropTarget::OnLeaveDef ScriptDropTarget::onLeaveThunk;
+	ScriptDropTarget::OnDropThunkDef ScriptDropTarget::onDropThunk;
+
+	ScriptDropTarget::ScriptDropTarget(MonoObject* instance, EditorWidgetBase* parent)
+		:ScriptObject(instance), mDropTarget(nullptr), mIsDestroyed(false)
+	{
+		mWidgetParentChangedConn = parent->onParentChanged.connect(std::bind(&ScriptDropTarget::widgetParentChanged, this, _1));
+		mWidgetResizedConn = parent->onResized.connect(std::bind(&ScriptDropTarget::widgetResized, this, _1, _2));
+
+		if (parent != nullptr)
+		{
+			EditorWindowBase* parentWindow = parent->getParentWindow();
+
+			if (parentWindow != nullptr)
+				setDropTarget(parentWindow->getRenderWindow(), 0, 0, 0, 0);
+		}
+	}
+
+	ScriptDropTarget::~ScriptDropTarget()
+	{
+		if (!mIsDestroyed)
+			destroy();
+	}
+
+	void ScriptDropTarget::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptDropTarget::internal_CreateInstance);
+		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptDropTarget::internal_Destroy);
+		metaData.scriptClass->addInternalCall("Internal_SetBounds", &ScriptDropTarget::internal_SetBounds);
+		metaData.scriptClass->addInternalCall("Internal_GetFilePaths", &ScriptDropTarget::internal_GetFilePaths);
+
+		onEnterThunk = (OnEnterThunkDef)metaData.scriptClass->getMethod("InternalDoOnEnter")->getThunk();
+		onMoveThunk = (OnMoveDef)metaData.scriptClass->getMethod("InternalDoOnDrag")->getThunk();
+		onLeaveThunk = (OnLeaveDef)metaData.scriptClass->getMethod("InternalDoOnLeave")->getThunk();
+		onDropThunk = (OnDropThunkDef)metaData.scriptClass->getMethod("InternalDoOnDrop")->getThunk();
+	}
+
+	void ScriptDropTarget::internal_CreateInstance(MonoObject* instance, ScriptEditorWindow* editorWindow)
+	{
+		ScriptDropTarget* nativeInstance = new (bs_alloc<ScriptDropTarget>()) ScriptDropTarget(instance, editorWindow->getEditorWidget());
+	}
+
+	void ScriptDropTarget::internal_Destroy(ScriptDropTarget* nativeInstance)
+	{
+		if (nativeInstance->mIsDestroyed)
+			return;
+
+		nativeInstance->destroy();
+	}
+
+	void ScriptDropTarget::internal_SetBounds(ScriptDropTarget* nativeInstance, Rect2I bounds)
+	{
+		if (nativeInstance->mIsDestroyed)
+			return;
+
+		nativeInstance->setBounds(bounds);
+	}
+
+	MonoArray* ScriptDropTarget::internal_GetFilePaths(ScriptDropTarget* nativeInstance)
+	{
+		OSDropTarget* dropTarget = nativeInstance->mDropTarget;
+
+		if (nativeInstance->mIsDestroyed || dropTarget == nullptr || dropTarget->getDropType() != OSDropType::FileList)
+			return ScriptArray::create<String>(0).getInternal();
+
+		Vector<WString> fileList = dropTarget->getFileList();
+		ScriptArray output = ScriptArray::create<WString>((UINT32)fileList.size());
+
+		UINT32 idx = 0;
+		for (auto& path : fileList)
+		{
+			output.set(idx, path);
+			idx++;
+		}
+
+		return output.getInternal();
+	}
+
+	void ScriptDropTarget::destroy()
+	{
+		mIsDestroyed = true;
+
+		mWidgetParentChangedConn.disconnect();
+		mWidgetResizedConn.disconnect();
+
+		setDropTarget(nullptr, 0, 0, 0, 0);
+	}
+
+	void ScriptDropTarget::setDropTarget(const RenderWindowPtr& parentWindow, INT32 x, INT32 y, UINT32 width, UINT32 height)
+	{
+		if (mDropTarget != nullptr)
+		{
+			Platform::destroyDropTarget(*mDropTarget);
+
+			mDropTargetEnterConn.disconnect();
+			mDropTargetLeaveConn.disconnect();
+			mDropTargetMoveConn.disconnect();
+			mDropTargetDroppedConn.disconnect();
+		}
+
+		if (parentWindow != nullptr)
+		{
+			mDropTarget = &Platform::createDropTarget(parentWindow.get(), x, y, width, height);
+
+			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&ScriptDropTarget::dropTargetDragMove, getManagedInstance(), _1, _2));
+			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&ScriptDropTarget::dropTargetDragMove, getManagedInstance(), _1, _2));
+			mDropTargetLeaveConn = mDropTarget->onLeave.connect(std::bind(&ScriptDropTarget::dropTargetDragLeave, getManagedInstance()));
+			mDropTargetDroppedConn = mDropTarget->onDrop.connect(std::bind(&ScriptDropTarget::dropTargetDragDropped, getManagedInstance(), _1, _2));
+		}
+		else
+			mDropTarget = nullptr;
+	}
+
+	void ScriptDropTarget::setBounds(const Rect2I& bounds)
+	{
+		mArea = bounds;
+
+		Rect2I clippedArea = mArea;
+		clippedArea.clip(mParentArea);
+
+		if (mDropTarget != nullptr)
+			mDropTarget->setArea(mParentArea.x + clippedArea.x, mParentArea.y + clippedArea.y, clippedArea.width, clippedArea.height);
+	}
+
+	void ScriptDropTarget::dropTargetDragEnter(MonoObject* instance, INT32 x, INT32 y)
+	{
+		MonoException* exception = nullptr;
+		onEnterThunk(instance, x, y, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+
+	void ScriptDropTarget::dropTargetDragMove(MonoObject* instance, INT32 x, INT32 y)
+	{
+		MonoException* exception = nullptr;
+		onMoveThunk(instance, x, y, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+
+	void ScriptDropTarget::dropTargetDragLeave(MonoObject* instance)
+	{
+		MonoException* exception = nullptr;
+		onLeaveThunk(instance, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+
+	void ScriptDropTarget::dropTargetDragDropped(MonoObject* instance, INT32 x, INT32 y)
+	{
+		MonoException* exception = nullptr;
+		onDropThunk(instance, x, y, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+
+	void ScriptDropTarget::widgetParentChanged(EditorWidgetContainer* parent)
+	{
+		RenderWindowPtr parentRenderWindow;
+		if (parent != nullptr)
+		{
+			EditorWindowBase* parentWindow = parent->getParentWindow();
+
+			if (parentWindow != nullptr)
+				parentRenderWindow = parentWindow->getRenderWindow();
+		}
+
+		Rect2I clippedArea = mArea;
+		if (parentRenderWindow == nullptr)
+			mParentArea = Rect2I();
+		
+		clippedArea.clip(mParentArea);
+
+		setDropTarget(parentRenderWindow, mParentArea.x + clippedArea.x, mParentArea.y + clippedArea.y, clippedArea.width, clippedArea.height);
+	}
+
+	void ScriptDropTarget::widgetResized(UINT32 width, UINT32 height)
+	{
+		mParentArea.width = width;
+		mParentArea.height = height;
+
+		setBounds(mArea);
+	}
+}

+ 18 - 0
TODO.txt

@@ -15,6 +15,24 @@ the same and the only variable will be the 4byte random number, which can someti
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Project window
 Project window
 
 
+C# DropTarget
+ - Requires an EditorWindow parent (so I can retrieve its coordinates)
+ - Bounds - settable area relative to the parent window
+ - Callbacks for OnEnter, OnLeave, OnDrag, OnDrop
+ - C# version only works for file drop types, others are ignored
+ - GetDroppedFiles() returns a list of paths
+
+Need faster GUILayoutUtility::calcBounds:
+ - WAY too much recursion and repetition
+  - Algorithm is 2 * n^3!!
+  - One N for calcBounds recursion
+  - One N for iteration over children for _calculateLayoutSizeRange (multiplied by two as I do it twice in each calcBounds call)
+  - One N for _calculateLayoutSizeRange itself being recursive
+ - Consider an algorithm that first locates the parent GUIPanel and then traverses down
+ - Extend _calculateLayoutSizeRange so it can accept a precalculated array of child size ranges
+  - Then I can hopefully avoid repetition and also merge two code paths for layout size range calculation
+ - CONSIDER actually performing the layout update, and just caching the results
+
 Simple tasks:
 Simple tasks:
  - Add C# Renderable & Material interface
  - Add C# Renderable & Material interface
  - Add C# context menu support for GUI elements
  - Add C# context menu support for GUI elements