ソースを参照

Added tracking of editor widget focus and a way to transform screen to widget coordinates

Marko Pintera 11 年 前
コミット
49c177131f

+ 6 - 0
BansheeEditor/Include/BsEditorWidget.h

@@ -16,12 +16,17 @@ namespace BansheeEngine
 		INT32 getY() const { return mY; }
 		UINT32 getWidth() const { return mWidth; }
 		UINT32 getHeight() const { return mHeight; }
+		bool hasFocus() const { return mHasFocus; }
 
 		void _setSize(UINT32 width, UINT32 height);
 		void _setPosition(INT32 x, INT32 y);
 		void _changeParent(EditorWidgetContainer* parent);
+		void _setHasFocus(bool focus) { mHasFocus = focus; }
 		EditorWidgetContainer* _getParent() const { return mParent; }
 
+		Vector2I screenToWidgetPos(const Vector2I& screenPos) const;
+		Vector2I widgetToScreenPos(const Vector2I& widgetPos) const;
+
 		void _disable();
 		void _enable();
 
@@ -48,6 +53,7 @@ namespace BansheeEngine
 		INT32 mX, mY;
 		UINT32 mWidth, mHeight;
 		GUIArea* mContent;
+		bool mHasFocus;
 
 		GUIWidget& getParentWidget() const;
 

+ 1 - 0
BansheeEditor/Include/BsEditorWidgetContainer.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 
 		UINT32 getNumWidgets() const { return (UINT32)mWidgets.size(); }
 		EditorWidgetBase* getWidget(UINT32 idx) const;
+		EditorWidgetBase* getActiveWidget() const;
 		GUIWidget& getParentWidget() const { return *mParent; }
 		EditorWindow* getParentWindow() const { return mParentWindow; }
 

+ 17 - 0
BansheeEditor/Include/BsEditorWidgetManager.h

@@ -68,9 +68,26 @@ namespace BansheeEngine
 		static void preRegisterWidget(const String& name, std::function<EditorWidgetBase*(EditorWidgetContainer&)> createCallback);
 
 	private:
+		/**
+		 * @brief	Called whenever a pointer (e.g. mouse cursor) is moved.
+		 */
+		void onPointerMoved(const PointerEvent& event);
+
+		/**
+		 * @brief	Called whenever a pointer button (e.g. mouse button) is released.
+		 */
+		void onPointerReleased(const PointerEvent& event);
+
+		/**
+		 * @brief	Called whenever a pointer button (e.g. mouse button) is pressed.
+		 */
+		void onPointerPressed(const PointerEvent& event);
+
 		Map<String, EditorWidgetBase*> mActiveWidgets;
 		Map<String, std::function<EditorWidgetBase*(EditorWidgetContainer&)>> mCreateCallbacks;
 
+		HEvent mOnPointerPressedConn;
+
 		static Stack<std::pair<String, std::function<EditorWidgetBase*(EditorWidgetContainer&)>>> QueuedCreateCallbacks;
 	};
 }

+ 6 - 0
BansheeEditor/Include/BsEditorWindowBase.h

@@ -26,6 +26,12 @@ namespace BansheeEngine
 		 * @brief	Called once every frame. Internal method.
 		 */
 		virtual void update() { }
+
+		/**
+		 * @brief	Returns the render window that this editor window is being rendered to.
+		 */
+		RenderWindowPtr _getRenderWindow() const { return mRenderWindow; }
+
 	protected:
 		EditorWindowBase();
 		EditorWindowBase(const RenderWindowPtr& renderWindow);

+ 27 - 1
BansheeEditor/Source/BsEditorWidget.cpp

@@ -8,11 +8,13 @@
 #include "BsGUIArea.h"
 #include "BsEditorWidgetContainer.h"
 #include "BsEditorWidgetManager.h"
+#include "BsEditorWindow.h"
+#include "BsRenderWindow.h"
 
 namespace BansheeEngine
 {
 	EditorWidgetBase::EditorWidgetBase(const HString& displayName, const String& name, EditorWidgetContainer& parentContainer)
-		:mDisplayName(displayName), mName(name), mParent(nullptr), mContent(nullptr), mX(0), mY(0), mWidth(0), mHeight(0)
+		:mDisplayName(displayName), mName(name), mParent(nullptr), mContent(nullptr), mX(0), mY(0), mWidth(0), mHeight(0), mHasFocus(false)
 	{
 		parentContainer.add(*this);
 	}
@@ -62,6 +64,30 @@ namespace BansheeEngine
 		doOnResized(width, height);
 	}
 
+	Vector2I EditorWidgetBase::screenToWidgetPos(const Vector2I& screenPos) const
+	{
+		EditorWindow* parentEditorWindow = mParent->getParentWindow();
+		RenderWindowPtr parentRenderWindow = parentEditorWindow->_getRenderWindow();
+
+		Vector2I windowPos = parentRenderWindow->screenToWindowPos(screenPos);
+		windowPos.x -= mX;
+		windowPos.y -= mY;
+
+		return windowPos;
+	}
+
+	Vector2I EditorWidgetBase::widgetToScreenPos(const Vector2I& widgetPos) const
+	{
+		EditorWindow* parentEditorWindow = mParent->getParentWindow();
+		RenderWindowPtr parentRenderWindow = parentEditorWindow->_getRenderWindow();
+
+		Vector2I windowPos = widgetPos;
+		windowPos.x += mX;
+		windowPos.y += mY;
+
+		return parentRenderWindow->windowToScreenPos(windowPos);
+	}
+
 	void EditorWidgetBase::doOnMoved(INT32 x, INT32 y)
 	{
 		if (!onMoved.empty())

+ 13 - 0
BansheeEditor/Source/BsEditorWidgetContainer.cpp

@@ -135,6 +135,19 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	EditorWidgetBase* EditorWidgetContainer::getActiveWidget() const
+	{
+		if (mActiveWidget >= 0)
+		{
+			auto iterFind = mWidgets.find(mActiveWidget);
+
+			if (iterFind != mWidgets.end())
+				return iterFind->second;
+		}
+
+		return nullptr;
+	}
+
 	void EditorWidgetContainer::setSize(UINT32 width, UINT32 height)
 	{
 		// TODO - Title bar is always TitleBarHeight size, so what happens when the container area is smaller than that?

+ 50 - 0
BansheeEditor/Source/BsEditorWidgetManager.cpp

@@ -7,6 +7,11 @@
 #include "BsEditorWidgetLayout.h"
 #include "BsDockManager.h"
 #include "BsException.h"
+#include "BsInput.h"
+#include "BsRenderWindow.h"
+#include "BsVector2I.h"
+
+using namespace std::placeholders;
 
 namespace BansheeEngine
 {
@@ -21,10 +26,14 @@ namespace BansheeEngine
 
 			registerWidget(curElement.first, curElement.second);
 		}
+
+		mOnPointerPressedConn = gInput().onPointerPressed.connect(std::bind(&EditorWidgetManager::onPointerPressed, this, _1));
 	}
 
 	EditorWidgetManager::~EditorWidgetManager()
 	{
+		mOnPointerPressedConn.disconnect();
+
 		Map<String, EditorWidgetBase*> widgetsCopy = mActiveWidgets;
 
 		for (auto& widget : widgetsCopy)
@@ -203,6 +212,47 @@ namespace BansheeEngine
 		}
 	}
 
+	void EditorWidgetManager::onPointerPressed(const PointerEvent& event)
+	{
+		for (auto& widgetData : mActiveWidgets)
+		{
+			EditorWidgetBase* widget = widgetData.second;
+			EditorWidgetContainer* parentContainer = widget->_getParent();
+			EditorWindow* parentWindow = parentContainer->getParentWindow();
+
+			if (parentWindow == nullptr)
+			{
+				widget->_setHasFocus(false);
+				continue;
+			}
+
+			RenderWindowPtr parentRenderWindow = parentWindow->_getRenderWindow();
+			const RenderWindowProperties& props = parentRenderWindow->getProperties();
+
+			if (!props.hasFocus())
+			{
+				widget->_setHasFocus(false);
+				continue;
+			}
+
+			if (parentContainer->getActiveWidget() != widget)
+			{
+				widget->_setHasFocus(false);
+				continue;
+			}
+
+			Vector2I widgetPos = widget->screenToWidgetPos(event.screenPos);
+			if (widgetPos.x >= 0 && widgetPos.y >= 0 
+				&& widgetPos.x < (INT32)widget->getWidth() 
+				&& widgetPos.y < (INT32)widget->getHeight())
+			{
+				widget->_setHasFocus(true);
+			}
+			else
+				widget->_setHasFocus(false);
+		}
+	}
+
 	void EditorWidgetManager::preRegisterWidget(const String& name, std::function<EditorWidgetBase*(EditorWidgetContainer&)> createCallback)
 	{
 		QueuedCreateCallbacks.push(std::pair<String, std::function<EditorWidgetBase*(EditorWidgetContainer&)>>(name, createCallback));

+ 0 - 1
BansheeEditor/Source/BsGizmoManager.cpp

@@ -263,7 +263,6 @@ namespace BansheeEngine
 					if (wireMeshProxy == nullptr)
 						wireMeshProxy = meshData.mesh->_createProxy(0);
 				}
-
 			}
 
 			// Since there is no sorting used with draw helper meshes we only expect up to two of them,

+ 23 - 3
MBansheeEditor/EditorWindow.cs

@@ -6,8 +6,9 @@ namespace BansheeEditor
 {
     public class EditorWindow : ScriptObject
     {
-        internal int width { get { return Internal_GetWidth(mCachedPtr); } }
-        internal int height { get { return Internal_GetHeight(mCachedPtr); } }
+        public int Width { get { return Internal_GetWidth(mCachedPtr); } }
+        public int Height { get { return Internal_GetHeight(mCachedPtr); } }
+        public bool HasFocus { get { return Internal_HasFocus(mCachedPtr); } }
 
         protected GUIPanel GUI;
 
@@ -16,9 +17,19 @@ namespace BansheeEditor
             return (T)Internal_CreateOrGetInstance(typeof(T).Namespace, typeof(T).Name);
         }
 
+        public Vector2I ScreenToWindowPos(Vector2I screenPos)
+        {
+            return Internal_ScreenToWindowPos(mCachedPtr, screenPos);
+        }
+
+        public Vector2I WindowToScreenPos(Vector2I screenPos)
+        {
+            return Internal_WindowToScreenPos(mCachedPtr, screenPos);
+        }
+
         protected EditorWindow()
         {
-            GUI = CreatePanel(0, 0, width, height);
+            GUI = CreatePanel(0, 0, Width, Height);
         }
 
         protected virtual void WindowResized(int width, int height)
@@ -47,5 +58,14 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern int Internal_GetHeight(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_HasFocus(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector2I Internal_ScreenToWindowPos(IntPtr nativeInstance, Vector2I position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector2I Internal_WindowToScreenPos(IntPtr nativeInstance, Vector2I position);
     }
 }

+ 1 - 1
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -117,7 +117,7 @@ namespace BansheeEditor
                 if (!inspectorData[i].expanded)
                     inspectorHeight = 0;
 
-                inspectorData[i].inspector.SetArea(0, curPosition, width, inspectorHeight);
+                inspectorData[i].inspector.SetArea(0, curPosition, Width, inspectorHeight);
                 inspectorData[i].container.SetLayoutOptions(GUIOption.FixedHeight(inspectorHeight));
                 curPosition += inspectorHeight;
             } 

+ 4 - 0
SBansheeEditor/Include/BsScriptEditorWindow.h

@@ -3,6 +3,7 @@
 #include "BsScriptEditorPrerequisites.h"
 #include "BsScriptObject.h"
 #include "BsEditorWidget.h"
+#include "BsVector2I.h"
 
 namespace BansheeEngine
 {
@@ -30,6 +31,9 @@ namespace BansheeEngine
 
 		static MonoObject* internal_createOrGetInstance(MonoString* ns, MonoString* typeName);
 
+		static bool internal_hasFocus(ScriptEditorWindow* thisPtr);
+		static Vector2I internal_screenToWindowPos(ScriptEditorWindow* thisPtr, const Vector2I& screenPos);
+		static Vector2I internal_windowToScreenPos(ScriptEditorWindow* thisPtr, const Vector2I& windowPos);
 		static UINT32 internal_getWidth(ScriptEditorWindow* thisPtr);
 		static UINT32 internal_getHeight(ScriptEditorWindow* thisPtr);
 

+ 18 - 0
SBansheeEditor/Source/BsScriptEditorWindow.cpp

@@ -40,6 +40,9 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_InitializeGUIPanel", &ScriptEditorWindow::internal_initializeGUIPanel);
 		metaData.scriptClass->addInternalCall("Internal_GetWidth", &ScriptEditorWindow::internal_getWidth);
 		metaData.scriptClass->addInternalCall("Internal_GetHeight", &ScriptEditorWindow::internal_getHeight);
+		metaData.scriptClass->addInternalCall("Internal_HasFocus", &ScriptEditorWindow::internal_hasFocus);
+		metaData.scriptClass->addInternalCall("Internal_ScreenToWindowPos", &ScriptEditorWindow::internal_screenToWindowPos);
+		metaData.scriptClass->addInternalCall("Internal_WindowToScreenPos", &ScriptEditorWindow::internal_windowToScreenPos);
 
 		onResizedMethod = metaData.scriptClass->getMethod("WindowResized", 2);
 	}
@@ -70,6 +73,21 @@ namespace BansheeEngine
 		ScriptObject::_onManagedInstanceDeleted();
 	}
 
+	bool ScriptEditorWindow::internal_hasFocus(ScriptEditorWindow* thisPtr)
+	{
+		return thisPtr->getEditorWidget()->hasFocus();
+	}
+
+	Vector2I ScriptEditorWindow::internal_screenToWindowPos(ScriptEditorWindow* thisPtr, const Vector2I& screenPos)
+	{
+		return thisPtr->getEditorWidget()->screenToWidgetPos(screenPos);
+	}
+
+	Vector2I ScriptEditorWindow::internal_windowToScreenPos(ScriptEditorWindow* thisPtr, const Vector2I& windowPos)
+	{
+		return thisPtr->getEditorWidget()->widgetToScreenPos(windowPos);
+	}
+
 	UINT32 ScriptEditorWindow::internal_getWidth(ScriptEditorWindow* thisPtr)
 	{
 		return thisPtr->mEditorWidget->getWidth();

+ 2 - 0
SceneView.txt

@@ -2,6 +2,8 @@
  GIZMO TODO:
   - Make a C# wrapper for Camera and Renderable
 
+The bounds I retrieve from GUIUtility are relative to the entire window, not just the current widget. Another reason to move editor widgets to their own GUIWidget.
+
 Set up Application::getPrimaryViewport so it returns a valid viewport otherwise C# Camera won't work properly
 
 REFACTOR material getParams* and related classes. Those params should update all gpu program params that share that variable, not just the first found