Procházet zdrojové kódy

Proper screen <-> window coordinate transformations for modal windows
Updated GUILayoutUtility so it can return coordinates relative to a specific GUIPanel

Marko Pintera před 10 roky
rodič
revize
97a70b6f03

+ 10 - 0
BansheeEditor/Include/BsModalWindow.h

@@ -14,6 +14,16 @@ namespace BansheeEngine
 		virtual void close();
 		void setTitle(const HString& title);
 
+		/**
+		 * Converts screen pointer coordinates into coordinates relative to the window contents GUI panel.
+		 */
+		Vector2I screenToWindowPos(const Vector2I& screenPos) const;
+
+		/**
+		 * Converts pointer coordinates relative to the window contents GUI panel into screen coordinates.
+		 */
+		Vector2I windowToScreenPos(const Vector2I& windowPos) const;
+
 	protected:
 		friend class EditorWindowManager;
 

+ 24 - 0
BansheeEditor/Source/BsModalWindow.cpp

@@ -70,6 +70,30 @@ namespace BansheeEngine
 
 	}
 
+	Vector2I ModalWindow::screenToWindowPos(const Vector2I& screenPos) const
+	{
+		Vector2I renderWindowPos = getRenderWindow()->screenToWindowPos(screenPos);
+
+		Vector2I contentsPos = renderWindowPos;
+		Rect2I contentArea = getContentArea();
+
+		contentsPos.x -= contentArea.x;
+		contentsPos.y -= contentArea.y;
+
+		return contentsPos;
+	}
+
+	Vector2I ModalWindow::windowToScreenPos(const Vector2I& windowPos) const
+	{
+		Vector2I contentsPos = windowPos;
+		Rect2I contentArea = getContentArea();
+
+		contentsPos.x += contentArea.x;
+		contentsPos.y += contentArea.y;
+
+		return getRenderWindow()->windowToScreenPos(contentsPos);
+	}
+
 	void ModalWindow::update()
 	{
 

+ 6 - 1
BansheeEngine/Include/BsGUILayoutUtility.h

@@ -21,12 +21,17 @@ namespace BansheeEngine
 		/**
 		 * Calculates position and size of a GUI element in its current layout.
 		 * Returned position is relative to parent GUI panel.
+		 *
+		 * @param	elem		Element to calculate bounds for.
+		 * @param	relativeTo	Parent panel of the provided element relative to which to return the
+		 *						bounds. If null the bounds relative to the first parent panel are returned.
+		 *						Behavior is undefined if provided panel is not a parent of the element.
 		 */
 		// TODO - This method might fail if element is part of a more complex hierarchy
 		// other than just GUILayouts and base elements (e.g. a tree view) because for a lot
 		// of such custom container elements like tree view don't have method for calculating 
 		// element bounds implemented
-		static Rect2I calcBounds(const GUIElementBase* elem);
+		static Rect2I calcBounds(const GUIElementBase* elem, GUIPanel* relativeTo = nullptr);
 
 		/**
 		 * @brief	Calculates the actual size of the layout taken up by all of its elements.

+ 4 - 2
BansheeEngine/Source/BsGUILayoutUtility.cpp

@@ -5,6 +5,7 @@
 #include "BsGUIElementStyle.h"
 #include "BsGUIWidget.h"
 #include "BsViewport.h"
+#include "BsGUIPanel.h"
 
 namespace BansheeEngine
 {
@@ -13,7 +14,7 @@ namespace BansheeEngine
 		return elem->_calculateLayoutSizeRange().optimal;
 	}
 
-	Rect2I GUILayoutUtility::calcBounds(const GUIElementBase* elem)
+	Rect2I GUILayoutUtility::calcBounds(const GUIElementBase* elem, GUIPanel* relativeTo)
 	{
 		Rect2I parentArea;
 
@@ -22,7 +23,8 @@ namespace BansheeEngine
 		{
 			parentArea = calcBounds(parent);
 
-			if (parent->_getType() == GUIElementBase::Type::Panel)
+			// TODO - Implement this properly
+			if (parent->_getType() == GUIElementBase::Type::Panel && (relativeTo == nullptr || relativeTo == parent))
 			{
 				parentArea.x = 0;
 				parentArea.y = 0;

+ 7 - 3
MBansheeEngine/GUI/GUILayoutUtility.cs

@@ -15,10 +15,14 @@ namespace BansheeEngine
             return output;
         }
 
-        public static Rect2I CalculateBounds(GUIElement element)
+        public static Rect2I CalculateBounds(GUIElement element, GUIPanel relativeTo = null)
         {
+            IntPtr relativeToNative = IntPtr.Zero;
+            if (relativeTo != null)
+                relativeToNative = relativeTo.GetCachedPtr();
+
             Rect2I output;
-            Internal_CalculateBounds(element.GetCachedPtr(), out output);
+            Internal_CalculateBounds(element.GetCachedPtr(), relativeToNative, out output);
             return output;
         }
 
@@ -26,6 +30,6 @@ namespace BansheeEngine
         private static extern void Internal_CalculateOptimalSize(IntPtr element, out Vector2I output);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CalculateBounds(IntPtr element, out Rect2I output);
+        private static extern void Internal_CalculateBounds(IntPtr element, IntPtr relativeTo, out Rect2I output);
     }
 }

+ 8 - 4
SBansheeEditor/Source/BsScriptModalWindow.cpp

@@ -171,14 +171,18 @@ namespace BansheeEngine
 
 	void ScriptModalWindow::internal_screenToWindowPos(ScriptModalWindow* thisPtr, Vector2I screenPos, Vector2I* windowPos)
 	{
-		RenderWindowPtr parentRenderWindow = thisPtr->mModalWindow->getRenderWindow();
-		*windowPos = parentRenderWindow->screenToWindowPos(screenPos);
+		if (thisPtr->mModalWindow != nullptr)
+			*windowPos = thisPtr->mModalWindow->screenToWindowPos(screenPos);
+		else
+			*windowPos = screenPos;
 	}
 
 	void ScriptModalWindow::internal_windowToScreenPos(ScriptModalWindow* thisPtr, Vector2I windowPos, Vector2I* screenPos)
 	{
-		RenderWindowPtr parentRenderWindow = thisPtr->mModalWindow->getRenderWindow();
-		*screenPos = parentRenderWindow->windowToScreenPos(windowPos);
+		if (thisPtr->mModalWindow != nullptr)
+			*screenPos = thisPtr->mModalWindow->windowToScreenPos(windowPos);
+		else
+			*screenPos = windowPos;
 	}
 
 	ManagedModalWindow::ManagedModalWindow(bool allowCloseButton, MonoObject* managedInstance)

+ 1 - 1
SBansheeEngine/Include/BsScriptGUILayoutUtility.h

@@ -17,6 +17,6 @@ namespace BansheeEngine
 
 	private:
 		static void internal_CalculateOptimalSize(ScriptGUIElementBaseTBase* guiElement, Vector2I* output);
-		static void internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, Rect2I* output);
+		static void internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, ScriptGUILayout* relativeTo, Rect2I* output);
 	};
 }

+ 9 - 2
SBansheeEngine/Source/BsScriptGUILayoutUtility.cpp

@@ -5,6 +5,9 @@
 #include "BsMonoManager.h"
 #include "BsMonoUtil.h"
 #include "BsScriptGUIElement.h"
+#include "BsGUIPanel.h"
+#include "BsGUIElementBase.h"
+#include "BsScriptGUILayout.h"
 #include "BsGUILayoutUtility.h"
 
 namespace BansheeEngine
@@ -24,8 +27,12 @@ namespace BansheeEngine
 		*output = GUILayoutUtility::calcOptimalSize(guiElement->getGUIElement());;
 	}
 
-	void ScriptGUILayoutUtility::internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, Rect2I* output)
+	void ScriptGUILayoutUtility::internal_CalculateBounds(ScriptGUIElementBaseTBase* guiElement, ScriptGUILayout* relativeTo, Rect2I* output)
 	{
-		*output = GUILayoutUtility::calcBounds(guiElement->getGUIElement());
+		GUIPanel* relativeToPanel = nullptr;
+		if (relativeTo != nullptr)
+			relativeToPanel = static_cast<GUIPanel*>(relativeTo->getGUIElement());
+
+		*output = GUILayoutUtility::calcBounds(guiElement->getGUIElement(), relativeToPanel);
 	}
 }

+ 0 - 3
TODO.txt

@@ -17,9 +17,6 @@ the same and the only variable will be the 4byte random number, which can someti
 ----------------------------------------------------------------------
 GUIArea refactor:
 
-EditorWindow and ModalWindow need to initialize the C# "GUI" field.
- - Check if the default GUIPanel has proper size. EditorWindow should be fine, but modal window might need additional handling (I don't think it even has a default contents panel)
-
 ColorPicker 2D handle is broken because it uses window coordinates for positioning, but it needs coordinates relative to parent GUI panel
  - Will likely need a new method for that
  - Extend GUILayoutUtility::calcBounds so it can returns bounds relative to specific GUIPanel