Răsfoiți Sursa

Moved GUIManager to callbacks

Marko Pintera 12 ani în urmă
părinte
comite
05a77f5c18

+ 14 - 1
BansheeEngine/Include/BsGUIManager.h

@@ -6,6 +6,7 @@
 #include "CmModule.h"
 #include "CmInputHandler.h"
 #include "CmDeferredRenderContextFwd.h"
+#include <boost/signals/connection.hpp>
 
 namespace BansheeEngine
 {
@@ -54,15 +55,27 @@ namespace BansheeEngine
 		GUIElement* mKeyboardFocusElement;
 
 		bool mSeparateMeshesByWidget;
-		bool mLastFrameButtonState[CM::MB_Count];
 		CM::Int2 mLastCursorLocalPos;
 
 		GUIMouseEvent mMouseEvent;
 		GUIKeyEvent mKeyEvent;
 
+		boost::signals::connection mOnMouseMovedConn;
+		boost::signals::connection mOnMouseDownConn;
+		boost::signals::connection mOnMouseUpConn;
+		boost::signals::connection mOnKeyDownConn;
+		boost::signals::connection mOnKeyUpConn;
+
 		void updateMeshes();
 		void updateInput();
 
+		void onKeyDown(CM::KeyCode keyCode);
+		void onKeyUp(CM::KeyCode keyCode);
+
+		void onMouseMoved(const CM::MouseEvent& event);
+		void onMouseDown(const CM::MouseEvent& event, CM::MouseButton buttonID);
+		void onMouseUp(const CM::MouseEvent& event, CM::MouseButton buttonID);
+
 		CM::Int2 getWidgetRelativeCursorPos(const GUIWidget& widget);
 	};
 }

+ 2 - 2
BansheeEngine/Source/BsApplication.cpp

@@ -32,12 +32,12 @@ namespace BansheeEngine
 		desc.importers.push_back("CamelotFBXImporter");
 		desc.importers.push_back("CamelotFontImporter");
 
+		CM::gApplication().startUp(desc);
+
 		GUIManager::startUp(cm_new<GUIManager>());
 		GUIMaterialManager::startUp(cm_new<GUIMaterialManager>());
 		OverlayManager::startUp(cm_new<OverlayManager>());
 
-		CM::gApplication().startUp(desc);
-
 		BuiltinMaterialManager::startUp(cm_new<BuiltinMaterialManager>());
 		BuiltinMaterialManager::instance().addFactory(cm_new<D3D9BuiltinMaterialFactory>());
 		BuiltinMaterialManager::instance().addFactory(cm_new<D3D11BuiltinMaterialFactory>());

+ 115 - 82
BansheeEngine/Source/BsGUIManager.cpp

@@ -44,13 +44,20 @@ namespace BansheeEngine
 		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
 		mActiveWidget(nullptr), mActiveMouseButton(0), mKeyboardFocusElement(nullptr), mKeyboardFocusWidget(nullptr)
 	{
-		for(int i = 0; i < MB_Count; i++)
-			mLastFrameButtonState[i] = false;
+		mOnKeyDownConn = gInput().onKeyDown.connect(boost::bind(&GUIManager::onKeyDown, this, _1));
+		mOnKeyUpConn = gInput().onKeyUp.connect(boost::bind(&GUIManager::onKeyUp, this, _1));
+		mOnMouseMovedConn = gInput().onMouseMoved.connect(boost::bind(&GUIManager::onMouseMoved, this, _1));
+		mOnMouseDownConn = gInput().onMouseDown.connect(boost::bind(&GUIManager::onMouseDown, this, _1, _2));
+		mOnMouseUpConn = gInput().onMouseUp.connect(boost::bind(&GUIManager::onMouseUp, this, _1, _2));
 	}
 
 	GUIManager::~GUIManager()
 	{
-
+		mOnKeyDownConn.disconnect();
+		mOnKeyUpConn.disconnect();
+		mOnMouseMovedConn.disconnect();
+		mOnMouseDownConn.disconnect();
+		mOnMouseUpConn.disconnect();
 	}
 
 	void GUIManager::registerWidget(GUIWidget* widget)
@@ -400,6 +407,29 @@ namespace BansheeEngine
 
 	void GUIManager::updateInput()
 	{
+
+	}
+
+	void GUIManager::onKeyDown(KeyCode keyCode)
+	{
+		//if(mKeyboardFocusElement != nullptr)
+		//{
+		//	mKeyEvent = GUIKeyEvent();
+
+		//	// TODO - Handle KeyUp/KeyDown states
+
+		//	mKeyEvent.setTextInputData(gInput().getInputString());
+		//	mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+		//}
+	}
+
+	void GUIManager::onKeyUp(KeyCode keyCode)
+	{
+
+	}
+
+	void GUIManager::onMouseMoved(const MouseEvent& event)
+	{
 #if CM_DEBUG_MODE
 		// Checks if all referenced windows actually exist
 		vector<RenderWindow*>::type activeWindows = RenderWindowManager::instance().getRenderWindows();
@@ -414,6 +444,14 @@ namespace BansheeEngine
 			}
 		}
 #endif
+
+		// TODO - Maybe avoid querying these for every event separately?
+		bool buttonStates[(int)MB_Count];
+		for(int i = 0; i < MB_Count; i++)
+			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
+
+		mMouseEvent = GUIMouseEvent(buttonStates);
+
 		GUIWidget* widgetInFocus = nullptr;
 		GUIElement* topMostElement = nullptr;
 		Int2 screenPos;
@@ -434,6 +472,7 @@ namespace BansheeEngine
 		{
 			const RenderWindow* window = widgetInFocus->getOwnerWindow();
 
+			// TODO - Use position provided by mouse event
 			screenPos = Cursor::getWindowPosition(*window);
 			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 
@@ -471,16 +510,6 @@ namespace BansheeEngine
 			}
 		}
 
-		/************************************************************************/
-		/* 								MOUSE EVENTS                      		*/
-		/************************************************************************/
-
-		bool buttonStates[(int)MB_Count];
-		for(int i = 0; i < MB_Count; i++)
-			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
-
-		mMouseEvent = GUIMouseEvent(buttonStates);
-
 		// Send MouseOver/MouseOut events to any elements the mouse passes over, except when
 		// mouse is being held down, in which we only send them to the active element
 		if(topMostElement != mMouseOverElement)
@@ -536,93 +565,97 @@ namespace BansheeEngine
 			}
 		}
 
-		// Check for MouseDown and MouseUp events.
-		bool isAnyMouseButtonDown = false;
+		mMouseOverElement = topMostElement;
+		mMouseOverWidget = widgetInFocus;
+	}
+
+	void GUIManager::onMouseDown(const MouseEvent& event, MouseButton buttonID)
+	{
+		// TODO - Maybe avoid querying these for every event separately?
+		bool buttonStates[(int)MB_Count];
 		for(int i = 0; i < MB_Count; i++)
-		{
-			bool buttonDown = buttonStates[i];
-			if(mLastFrameButtonState[i] != buttonDown)
-			{
-				// Mouse button is being pressed
-				if(buttonDown)
-				{
-					isAnyMouseButtonDown = true;
+			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
 
-					// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
-					bool acceptMouseDown = mActiveElement == nullptr && topMostElement != nullptr;
-					if(acceptMouseDown)
-					{
-						mMouseEvent.setMouseDownData(topMostElement, localPos, (MouseButton)i);
-						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
+		mMouseEvent = GUIMouseEvent(buttonStates);
 
-						// DragStart is for all intents and purposes same as mouse down but since I need a DragEnd event, I feel a separate DragStart
-						// event was also needed to make things clearer.
-						mMouseEvent.setMouseDragStartData(topMostElement, localPos);
-						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
+		// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
+		bool acceptMouseDown = mActiveElement == nullptr && mMouseOverElement != nullptr;
+		if(acceptMouseDown)
+		{
+			// TODO - Use position provided by mouse event
+			Int2 screenPos = Cursor::getWindowPosition(*mMouseOverWidget->getOwnerWindow());
+			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 
-						mActiveElement = topMostElement;
-						mActiveWidget = widgetInFocus;
-						mActiveMouseButton = i;
+			const Matrix4& worldTfrm = mMouseOverWidget->SO()->getWorldTfrm();
 
-						mLastFrameButtonState[i] = buttonDown;
-					}
-				}
-				else
-				{
-					// Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
-					// And only activate when a button that originally caused the active state is released, otherwise ignore it.
-					bool acceptMouseUp = mActiveMouseButton == i && (topMostElement != nullptr && mActiveElement == topMostElement);
-					if(acceptMouseUp)
-					{
-						mMouseEvent.setMouseUpData(topMostElement, localPos, (MouseButton)i);
-						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
-					}
+			Vector4 vecLocalPos = worldTfrm.inverse() * vecScreenPos;
+			Int2 localPos = Int2(Math::RoundToInt(vecLocalPos.x), Math::RoundToInt(vecLocalPos.y));
 
-					// Send DragEnd event to whichever element is active
-					bool acceptEndDrag = mActiveMouseButton == i && mActiveElement != nullptr;
-					if(acceptEndDrag)
-					{
-						mMouseEvent.setMouseDragEndData(topMostElement, localPos);
-						mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
+			mMouseEvent.setMouseDownData(mMouseOverElement, localPos, buttonID);
+			mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 
-						mActiveElement = nullptr;
-						mActiveWidget = nullptr;
-						mActiveMouseButton = 0;
-					}	
-				}
+			// DragStart is for all intents and purposes same as mouse down but since I need a DragEnd event, I feel a separate DragStart
+			// event was also needed to make things clearer.
+			mMouseEvent.setMouseDragStartData(mMouseOverElement, localPos);
+			mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 
-				mLastFrameButtonState[i] = buttonDown;
-			}
+			mActiveElement = mMouseOverElement;
+			mActiveWidget = mMouseOverWidget;
+			mActiveMouseButton = (UINT32)buttonID;
 		}
 
-		mMouseOverElement = topMostElement;
-		mMouseOverWidget = widgetInFocus;
+		if(mKeyboardFocusElement != nullptr && mMouseOverElement != mKeyboardFocusElement)
+			mKeyboardFocusElement->_setFocus(false);
 
-		// Update keyboard focus if user has pressed any mouse button
-		if(isAnyMouseButtonDown)
+		if(mMouseOverElement != nullptr)
+			mMouseOverElement->_setFocus(true);
+
+		mKeyboardFocusElement = mMouseOverElement;
+		mKeyboardFocusWidget = mMouseOverWidget;
+	}
+
+	void GUIManager::onMouseUp(const MouseEvent& event, MouseButton buttonID)
+	{
+		// TODO - Maybe avoid querying these for every event separately?
+		bool buttonStates[(int)MB_Count];
+		for(int i = 0; i < MB_Count; i++)
+			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
+
+		mMouseEvent = GUIMouseEvent(buttonStates);
+
+		// TODO - Use position provided by mouse event
+		Int2 localPos;
+		if(mMouseOverWidget != nullptr)
 		{
-			if(mKeyboardFocusElement != nullptr && mMouseOverElement != mKeyboardFocusElement)
-				mKeyboardFocusElement->_setFocus(false);
+			Int2 screenPos = Cursor::getWindowPosition(*mMouseOverWidget->getOwnerWindow());
+			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 
-			if(mMouseOverElement != nullptr)
-				mMouseOverElement->_setFocus(true);
+			const Matrix4& worldTfrm = mMouseOverWidget->SO()->getWorldTfrm();
 
-			mKeyboardFocusElement = mMouseOverElement;
-			mKeyboardFocusWidget = mMouseOverWidget;
+			Vector4 vecLocalPos = worldTfrm.inverse() * vecScreenPos;
+			localPos = Int2(Math::RoundToInt(vecLocalPos.x), Math::RoundToInt(vecLocalPos.y));
 		}
 
-		/************************************************************************/
-		/* 								KEYBOARD EVENTS                    		*/
-		/************************************************************************/
-		if(mKeyboardFocusElement != nullptr)
+		// Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
+		// And only activate when a button that originally caused the active state is released, otherwise ignore it.
+		bool acceptMouseUp = mActiveMouseButton == (UINT32)buttonID && (mMouseOverElement != nullptr && mActiveElement == mMouseOverElement);
+		if(acceptMouseUp)
 		{
-			mKeyEvent = GUIKeyEvent();
-
-			// TODO - Handle KeyUp/KeyDown states
-			
-			mKeyEvent.setTextInputData(gInput().getInputString());
-			mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+			mMouseEvent.setMouseUpData(mMouseOverElement, localPos, buttonID);
+			mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 		}
+
+		// Send DragEnd event to whichever element is active
+		bool acceptEndDrag = mActiveMouseButton == (UINT32)buttonID && mActiveElement != nullptr;
+		if(acceptEndDrag)
+		{
+			mMouseEvent.setMouseDragEndData(mMouseOverElement, localPos);
+			mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
+
+			mActiveElement = nullptr;
+			mActiveWidget = nullptr;
+			mActiveMouseButton = 0;
+		}	
 	}
 
 	Int2 GUIManager::getWidgetRelativeCursorPos(const GUIWidget& widget)

+ 8 - 0
CamelotCore/Include/CmInput.h

@@ -13,6 +13,14 @@ namespace CamelotFramework
 		Input();
 		~Input();
 
+		boost::signal<void(KeyCode)> onKeyDown;
+		boost::signal<void(KeyCode)> onKeyUp;
+
+		boost::signal<void(const MouseEvent&)> onMouseMoved;
+		boost::signal<void(const MouseEvent&, MouseButton)> onMouseDown;
+		boost::signal<void(const MouseEvent&, MouseButton)> onMouseUp;
+
+
 		void initClipRect(Rect& clipRect);
 		void registerInputHandler(InputHandlerPtr inputHandler);
 

+ 3 - 0
CamelotCore/Include/CmRenderWindow.h

@@ -29,6 +29,7 @@ THE SOFTWARE
 #include "CmPrerequisites.h"
 
 #include "CmRenderTarget.h"
+#include "CmInt2.h"
 
 namespace CamelotFramework
 {
@@ -178,6 +179,8 @@ namespace CamelotFramework
 		void setHasFocus(bool focus);
 		bool hasFocus() const { return mHasFocus; }
 
+		virtual Int2 screenToWindowPos(const Int2& screenPos) const = 0;
+
 		mutable boost::signal<void(RenderWindow*)> onFocusChanged;
 
 		virtual void destroy();

+ 1 - 1
CamelotCore/Source/CmApplication.cpp

@@ -89,6 +89,7 @@ namespace CamelotFramework
 
 		while(mRunMainLoop)
 		{
+			gInput().update();
 			gSceneManager().update();
 
 			if(!mainLoopCallback.empty())
@@ -121,7 +122,6 @@ namespace CamelotFramework
 				mPrimaryRenderContext->cancelAll();
 
 			gTime().update();
-			gInput().update();
 		}
 	}
 

+ 5 - 0
CamelotCore/Source/CmInput.cpp

@@ -81,11 +81,13 @@ namespace CamelotFramework
 	void Input::keyDown(KeyCode keyCode)
 	{
 		mKeyState[keyCode] = true;
+		onKeyDown(keyCode);
 	}
 
 	void Input::keyUp(KeyCode keyCode)
 	{
 		mKeyState[keyCode] = false;
+		onKeyUp(keyCode);
 	}
 
 	void Input::mouseMoved(const MouseEvent& event)
@@ -96,6 +98,7 @@ namespace CamelotFramework
 				return;
 		}
 
+		onMouseMoved(event);
 		mMouseLastRel = Int2(-event.relCoords.x, -event.relCoords.y);
 	}
 
@@ -108,6 +111,7 @@ namespace CamelotFramework
 		}
 
 		mMouseButtonState[buttonID] = true;
+		onMouseDown(event, buttonID);
 	}
 
 	void Input::mouseUp(const MouseEvent& event, MouseButton buttonID)
@@ -119,6 +123,7 @@ namespace CamelotFramework
 		}
 
 		mMouseButtonState[buttonID] = false;
+		onMouseUp(event, buttonID);
 	}
 
 	float Input::getHorizontalAxis() const

+ 2 - 0
CamelotD3D11RenderSystem/Include/CmD3D11RenderWindow.h

@@ -25,6 +25,8 @@ namespace CamelotFramework
 		bool isClosed() const									{ return mClosed; }
 		bool isHidden() const									{ return mHidden; }
 
+		Int2 screenToWindowPos(const Int2& screenPos) const;
+
 		void getCustomAttribute( const String& name, void* pData ) const;
 		DXGI_SWAP_CHAIN_DESC* getPresentationParameters(void)	{ return &mSwapChainDesc; }
 		HWND getWindowHandle() const							{ return mHWnd; }

+ 12 - 0
CamelotD3D11RenderSystem/Source/CmD3D11RenderWindow.cpp

@@ -536,6 +536,18 @@ namespace CamelotFramework
 		SAFE_RELEASE(backbuffer);
 	}
 
+	Int2 D3D11RenderWindow::screenToWindowPos(const Int2& screenPos) const
+	{
+		POINT pos;
+
+		// Convert client coordinates to screen coordinates
+		pos.x = screenPos.x;
+		pos.y = screenPos.y;
+
+		ClientToScreen(mHWnd, &pos);
+		return Int2(pos.x, pos.y);
+	}
+
 	void D3D11RenderWindow::_createSwapChain()
 	{
 		ZeroMemory(&mSwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

+ 2 - 0
CamelotD3D9Renderer/Include/CmD3D9RenderWindow.h

@@ -60,6 +60,8 @@ namespace CamelotFramework
 
 		void				swapBuffers();
 
+		Int2				screenToWindowPos(const Int2& screenPos) const;
+
 		// Method for dealing with resize / move & 3d library
 		void				windowMovedOrResized	();
 	

+ 12 - 0
CamelotD3D9Renderer/Source/CmD3D9RenderWindow.cpp

@@ -746,6 +746,18 @@ namespace CamelotFramework
 		}	
 	}
 
+	Int2 D3D9RenderWindow::screenToWindowPos(const Int2& screenPos) const
+	{
+		POINT pos;
+
+		// Convert client coordinates to screen coordinates
+		pos.x = screenPos.x;
+		pos.y = screenPos.y;
+
+		ClientToScreen(mHWnd, &pos);
+		return Int2(pos.x, pos.y);
+	}
+
 	//-----------------------------------------------------------------------------
 	bool D3D9RenderWindow::isNvPerfHUDEnable() const
 	{

+ 2 - 0
CamelotGLRenderer/Include/CmWin32Window.h

@@ -58,6 +58,8 @@ namespace CamelotFramework {
 		// Method for dealing with resize / move & 3d library
 		virtual void windowMovedOrResized(void);
 
+		Int2 screenToWindowPos(const Int2& screenPos) const;
+
 		void getCustomAttribute( const String& name, void* pData ) const;
 
         /** Used to set the active state of the render target.

+ 12 - 0
CamelotGLRenderer/Source/CmWin32Window.cpp

@@ -676,6 +676,18 @@ namespace CamelotFramework {
 		}
 	}
 
+	Int2 Win32Window::screenToWindowPos(const Int2& screenPos) const
+	{
+		POINT pos;
+
+		// Convert client coordinates to screen coordinates
+		pos.x = screenPos.x;
+		pos.y = screenPos.y;
+
+		ClientToScreen(mHWnd, &pos);
+		return Int2(pos.x, pos.y);
+	}
+
 	void Win32Window::getCustomAttribute( const String& name, void* pData ) const
 	{
 		if( name == "GLCONTEXT" ) {