Browse Source

Fixed an issue with non-client mouse events not having proper coordinates
Resizing a window now properly modifies its resize borders
Toggle menu bar line depending whether it's active or not

BearishSun 10 years ago
parent
commit
d1c685013d

+ 15 - 14
BansheeCore/Source/Win32/BsWin32Platform.cpp

@@ -548,14 +548,15 @@ namespace BansheeEngine
 	/**
 	 * @brief	Method triggered whenever a mouse event happens.
 	 */
-	void getMouseData(HWND hWnd, WPARAM wParam, LPARAM lParam, Vector2I& mousePos, OSPointerButtonStates& btnStates)
+	void getMouseData(HWND hWnd, WPARAM wParam, LPARAM lParam, bool nonClient, Vector2I& mousePos, OSPointerButtonStates& btnStates)
 	{
 		POINT clientPoint;
 
 		clientPoint.x = GET_X_LPARAM(lParam);
 		clientPoint.y = GET_Y_LPARAM(lParam); 
 
-		ClientToScreen(hWnd, &clientPoint);
+		if (!nonClient)
+			ClientToScreen(hWnd, &clientPoint);
 
 		mousePos.x = clientPoint.x;
 		mousePos.y = clientPoint.y;
@@ -874,7 +875,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, uMsg == WM_NCLBUTTONUP, intMousePos, btnStates);
 
 				if(!onCursorButtonReleased.empty())
 					onCursorButtonReleased(intMousePos, OSMouseButton::Left, btnStates);
@@ -892,7 +893,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, uMsg == WM_NCMBUTTONUP, intMousePos, btnStates);
 
 				if(!onCursorButtonReleased.empty())
 					onCursorButtonReleased(intMousePos, OSMouseButton::Middle, btnStates);
@@ -910,7 +911,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, uMsg == WM_NCRBUTTONUP, intMousePos, btnStates);
 
 				if(!onCursorButtonReleased.empty())
 					onCursorButtonReleased(intMousePos, OSMouseButton::Right, btnStates);
@@ -925,7 +926,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, true, intMousePos, btnStates);
 
 				if (!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Left, btnStates);
@@ -938,7 +939,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, false, intMousePos, btnStates);
 
 				if(!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Left, btnStates);
@@ -949,7 +950,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, true, intMousePos, btnStates);
 
 				if (!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Middle, btnStates);
@@ -962,7 +963,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, false, intMousePos, btnStates);
 
 				if(!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Middle, btnStates);
@@ -973,7 +974,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, true, intMousePos, btnStates);
 
 				if (!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Right, btnStates);
@@ -986,7 +987,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, false, intMousePos, btnStates);
 
 				if(!onCursorButtonPressed.empty())
 					onCursorButtonPressed(intMousePos, OSMouseButton::Right, btnStates);
@@ -997,7 +998,7 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, false, intMousePos, btnStates);
 
 				if(!onCursorDoubleClick.empty())
 					onCursorDoubleClick(intMousePos, btnStates);
@@ -1021,12 +1022,12 @@ namespace BansheeEngine
 				Vector2I intMousePos;
 				OSPointerButtonStates btnStates;
 				
-				getMouseData(hWnd, wParam, lParam, intMousePos, btnStates);
+				getMouseData(hWnd, wParam, lParam, uMsg == WM_NCMOUSEMOVE, intMousePos, btnStates);
 
 				if(!onCursorMoved.empty())
 					onCursorMoved(intMousePos, btnStates);
 
-				return true;
+				return 0;
 			}
 		case WM_MOUSEWHEEL:
 			{

+ 2 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -297,6 +297,7 @@
     <ClInclude Include="Include\BsGUIFloatField.h" />
     <ClInclude Include="Include\BsGUIComponentFoldout.h" />
     <ClInclude Include="Include\BsGUIFoldout.h" />
+    <ClInclude Include="Include\BsGUIHoverHitBox.h" />
     <ClInclude Include="Include\BsGUIIntField.h" />
     <ClInclude Include="Include\BsGUIDropButton.h" />
     <ClInclude Include="Include\BsGUIStatusBar.h" />
@@ -385,6 +386,7 @@
     <ClCompile Include="Source\BsGUIFloatField.cpp" />
     <ClCompile Include="Source\BsGUIComponentFoldout.cpp" />
     <ClCompile Include="Source\BsGUIFoldout.cpp" />
+    <ClCompile Include="Source\BsGUIHoverHitBox.cpp" />
     <ClCompile Include="Source\BsGUIIntField.cpp" />
     <ClCompile Include="Source\BsGUIMenuBar.cpp" />
     <ClCompile Include="Source\BsGUIDropButton.cpp" />

+ 6 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -288,6 +288,9 @@
     <ClInclude Include="Include\BsProjectSettingsRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIHoverHitBox.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorCommand.cpp">
@@ -515,5 +518,8 @@
     <ClCompile Include="Source\BsProjectSettings.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIHoverHitBox.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 1 - 0
BansheeEditor/Include/BsEditorPrerequisites.h

@@ -43,6 +43,7 @@ namespace BansheeEngine
 	class GUIFoldout;
 	class GUIStatusBar;
 	class GUIDropButton;
+	class GUIHoverHitBox;
 	class EditorWindowManager;
 	class DockManager;
 	class DockManagerLayout;

+ 53 - 0
BansheeEditor/Include/BsGUIHoverHitBox.h

@@ -0,0 +1,53 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsGUIElementContainer.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * Helper class used for detecting when mousing over a certain
+	 * and getting notified when that state changes. 
+	 */
+	class BS_ED_EXPORT GUIHoverHitBox : public GUIElementContainer
+	{
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * Creates a new hover hit box that will detect mouse hover/out events over certain area.
+		 */
+		static GUIHoverHitBox* create();
+
+		/**
+		 * Creates a new hover hit box that will detect mouse hover/out events over certain area.
+		 */
+		static GUIHoverHitBox* create(const GUIOptions& options);
+
+		/**
+		 * @brief	Triggered when pointer hovers over the hit box.
+		 */
+		Event<void()> onHover;
+
+		/**
+		 * @brief	Triggered when pointer that was previously hovering leaves the hit box.
+		 */
+		Event<void()> onOut;
+
+	private:
+		GUIHoverHitBox(const GUIDimensions& dimensions);
+
+		/**
+		 * @copydoc	GUIElementContainer::updateClippedBounds
+		 */
+		void updateClippedBounds() override;
+
+		/**
+		 * @copydoc	GUIElementContainer::_mouseEvent
+		 */
+		virtual bool _mouseEvent(const GUIMouseEvent& ev) override;
+	};
+}

+ 11 - 4
BansheeEditor/Include/BsGUIMenuBar.h

@@ -146,14 +146,19 @@ namespace BansheeEngine
 		void onSubMenuHover(const WString& name);
 
 		/**
-		 * @brief	Triggered when the user leaves the area of a menu item button.
+		 * @brief	Triggered when a sub-menu is closed.
 		 */
-		void onSubMenuOut();
+		void onSubMenuClosed();
 
 		/**
-		 * @brief	Triggered when a sub-menu is closed.
+		 * @brief	Triggered when the user enters the area of the menu bar.
 		 */
-		void onSubMenuClosed();
+		void onMenuBarHover();
+
+		/**
+		 * @brief	Triggered when the user leaves the area of the menu bar.
+		 */
+		void onMenuBarOut();
 
 		/**
 		 * @brief	Triggered when the minimize button is clicked.
@@ -190,12 +195,14 @@ namespace BansheeEngine
 
 		RenderWindow* mParentWindow;
 		CGUIWidget* mParentWidget;
+		GUIPanel* mOverlayPanel;
 		GUIPanel* mMainPanel;
 		GUIPanel* mBgPanel;
 		GUILayout* mMenuItemLayout;
 		GUITexture* mBgTexture;
 		GUITexture* mLogoTexture;
 		GUITexture* mSplitterLine;
+		GUIHoverHitBox* mHoverHitBox;
 
 		GUIButton* mMinBtn;
 		GUIButton* mMaxBtn;

+ 53 - 0
BansheeEditor/Source/BsGUIHoverHitBox.cpp

@@ -0,0 +1,53 @@
+#include "BsGUIHoverHitBox.h"
+#include "BsGUICommandEvent.h"
+#include "BsGUIMouseEvent.h"
+#include "BsCGUIWidget.h"
+#include "BsGUISkin.h"
+
+namespace BansheeEngine
+{
+	const String& GUIHoverHitBox::getGUITypeName()
+	{
+		static String name = "HoverHitBox";
+		return name;
+	}
+
+	GUIHoverHitBox* GUIHoverHitBox::create()
+	{
+		return new (bs_alloc<GUIHoverHitBox>()) GUIHoverHitBox(GUIDimensions::create());
+	}
+
+	GUIHoverHitBox* GUIHoverHitBox::create(const GUIOptions& options)
+	{
+		return new (bs_alloc<GUIHoverHitBox>()) GUIHoverHitBox(GUIDimensions::create(options));
+	}
+
+	GUIHoverHitBox::GUIHoverHitBox(const GUIDimensions& dimensions)
+		:GUIElementContainer(dimensions)
+	{
+
+	}
+
+	void GUIHoverHitBox::updateClippedBounds()
+	{
+		mClippedBounds = mLayoutData.area;
+	}
+
+	bool GUIHoverHitBox::_mouseEvent(const GUIMouseEvent& ev)
+	{
+		bool processed = GUIElementContainer::_mouseEvent(ev);
+
+		if (ev.getType() == GUIMouseEventType::MouseOver)
+		{
+			onHover();
+			return false;
+		}
+		else if (ev.getType() == GUIMouseEventType::MouseOut)
+		{
+			onOut();
+			return false;
+		}
+
+		return processed;
+	}
+};

+ 40 - 14
BansheeEditor/Source/BsGUIMenuBar.cpp

@@ -13,7 +13,8 @@
 #include "BsSceneObject.h"
 #include "BsPlatform.h"
 #include "BsCoreThread.h"
-#include <BsShortcutManager.h>
+#include "BsShortcutManager.h"
+#include "BsGUIHoverHitBox.h"
 
 namespace BansheeEngine
 {
@@ -48,17 +49,25 @@ namespace BansheeEngine
 		:mParentWidget(parent), mParentWindow(parentWindow), mMainPanel(nullptr), mMenuItemLayout(nullptr),
 		mBgTexture(nullptr), mLogoTexture(nullptr), mSubMenuOpen(false), mSubMenuButton(nullptr), mBgPanel(nullptr)
 	{
-		mMainPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 10);
+		mOverlayPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 10);
+		mOverlayPanel->setWidth(1);
+		mOverlayPanel->setHeight(50);
+
+		mMainPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 15);
+		mMainPanel->setWidth(1);
+		mMainPanel->setHeight(50);
+
+		mMainPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 15);
 		mMainPanel->setWidth(1);
 		mMainPanel->setHeight(50);
 
-		mBgPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 15);
+		mBgPanel = parent->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min() + 25);
 		mBgPanel->setWidth(1);
 		mBgPanel->setHeight(50);
 
 		mBgTexture = GUITexture::create(GUIImageScaleMode::StretchToFit,
 			GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), getBackgroundStyleType());
-
+		
 		GUILayoutX* bgLayout = mBgPanel->addNewElement<GUILayoutX>();
 		bgLayout->addElement(mBgTexture);
 
@@ -90,6 +99,12 @@ namespace BansheeEngine
 		mMaxBtn->onClick.connect(std::bind(&GUIMenuBar::onMaximizeClicked, this));
 		mCloseBtn->onClick.connect(std::bind(&GUIMenuBar::onCloseClicked, this));
 
+		mHoverHitBox = GUIHoverHitBox::create();
+		mOverlayPanel->addElement(mHoverHitBox);
+
+		mHoverHitBox->onHover.connect(std::bind(&GUIMenuBar::onMenuBarHover, this));
+		mHoverHitBox->onOut.connect(std::bind(&GUIMenuBar::onMenuBarOut, this));
+
 		refreshNonClientAreas();
 	}
 
@@ -176,7 +191,6 @@ namespace BansheeEngine
 		GUIButton* newButton = GUIButton::create(HString(name), "MenuBarBtn");
 		newButton->onClick.connect(std::bind(&GUIMenuBar::openSubMenu, this, name));
 		newButton->onHover.connect(std::bind(&GUIMenuBar::onSubMenuHover, this, name));
-		newButton->onOut.connect(std::bind(&GUIMenuBar::onSubMenuOut, this));
 
 		GUIFixedSpace* space = mMenuItemLayout->insertNewElement<GUIFixedSpace>(mMenuItemLayout->getNumChildren() - NUM_ELEMENTS_AFTER_CONTENT, ELEMENT_SPACING);
 		mMenuItemLayout->insertElement(mMenuItemLayout->getNumChildren() - NUM_ELEMENTS_AFTER_CONTENT, newButton);
@@ -347,14 +361,11 @@ namespace BansheeEngine
 
 			mSubMenuButton->_setOn(false);
 			mSubMenuOpen = false;
-			setActiveState(false);
 		}		
 	}
 
 	void GUIMenuBar::onSubMenuHover(const WString& name)
 	{
-		setActiveState(true);
-
 		if(mSubMenuOpen)
 		{
 			const GUIMenuBarData* subMenu = getSubMenu(name);
@@ -365,21 +376,29 @@ namespace BansheeEngine
 			if(mSubMenuButton != subMenu->button)
 				openSubMenu(name);
 		}
-	}
 
-	void GUIMenuBar::onSubMenuOut()
-	{
-		if (!mSubMenuOpen)
-			setActiveState(false);
+		setActiveState(true);
 	}
 
 	void GUIMenuBar::onSubMenuClosed()
 	{
 		mSubMenuButton->_setOn(false);
 		mSubMenuOpen = false;
+
 		setActiveState(false);
 	}
 
+	void GUIMenuBar::onMenuBarHover()
+	{
+		setActiveState(true);
+	}
+
+	void GUIMenuBar::onMenuBarOut()
+	{
+		if (!mSubMenuOpen)
+			setActiveState(false);
+	}
+
 	void GUIMenuBar::onMinimizeClicked()
 	{
 		mParentWindow->minimize(gCoreAccessor());
@@ -415,17 +434,24 @@ namespace BansheeEngine
 		Vector<Rect2I> nonClientAreas;
 		nonClientAreas.push_back(mLogoTexture->getBounds());
 
+		UINT32 menuWidth = 0;
 		if(mChildMenus.size() > 0)
 		{
 			Rect2I lastButtonBounds = mChildMenus.back().button->getBounds();
 			Rect2I minButtonBounds = mMinBtn->getBounds();
+			menuWidth = lastButtonBounds.x + lastButtonBounds.width;
 
-			Rect2I emptyArea(lastButtonBounds.x + lastButtonBounds.width, mainArea.y,
+			Rect2I emptyArea(menuWidth, mainArea.y,
 				minButtonBounds.x - (lastButtonBounds.x + lastButtonBounds.width), mainArea.height);
 
 			nonClientAreas.push_back(emptyArea);
 		}
 
 		Platform::setCaptionNonClientAreas(*mParentWindow->getCore(), nonClientAreas);
+
+		Rect2I menuBarBounds = mMenuItemLayout->getBounds();
+		menuBarBounds.width = menuWidth;
+
+		mHoverHitBox->setBounds(menuBarBounds);
 	}
 }

+ 4 - 6
BansheeEditor/Source/BsGUIWindowFrameWidget.cpp

@@ -60,13 +60,11 @@ namespace BansheeEngine
 		if (!mAllowResize)
 			return;
 
-		Rect2I bounds = mWindowFramePanel->getBounds();
+		INT32 x = 0;
+		INT32 y = 0;
 
-		INT32 x = bounds.x;
-		INT32 y = bounds.y;
-
-		UINT32 width = bounds.width;
-		UINT32 height = bounds.height;
+		UINT32 width = getTarget()->getWidth();
+		UINT32 height = getTarget()->getHeight();
 
 		Vector<NonClientResizeArea> nonClientAreas(8);
 

+ 11 - 0
BansheeEngine/Include/BsGUIDropDownHitBox.h

@@ -67,8 +67,19 @@ namespace BansheeEngine
 		 */
 		void updateClippedBounds() override;
 
+		/**
+		 * @copydoc	GUIElementContainer::_commandEvent
+		 */
 		virtual bool _commandEvent(const GUICommandEvent& ev) override;
+
+		/**
+		 * @copydoc	GUIElementContainer::_mouseEvent
+		 */
 		virtual bool _mouseEvent(const GUIMouseEvent& ev) override;
+
+		/**
+		 * @copydoc	GUIElementContainer::_isInBounds
+		 */
 		virtual bool _isInBounds(const Vector2I position) const override;
 
 		Vector<Rect2I> mBounds;

+ 6 - 0
BansheeEngine/Include/BsGUIElementBase.h

@@ -91,6 +91,12 @@ namespace BansheeEngine
 		 */
 		Rect2I getBounds(GUIPanel* relativeTo = nullptr);
 
+		/**
+		 * @brief	Sets the bounds of the GUI element. Relative to a parent GUI panel.
+		 * 			Equivalent to calling setPosition, setWidth and setHeight.
+		 */
+		void setBounds(const Rect2I& bounds);
+
 		/**
 		 * @brief	Returns non-clipped bounds of the GUI element. Relative to a parent GUI widget.
 		 *

+ 7 - 0
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -166,6 +166,13 @@ namespace BansheeEngine
 		return bounds;
 	}
 
+	void GUIElementBase::setBounds(const Rect2I& bounds)
+	{
+		setPosition(bounds.x, bounds.y);
+		setWidth(bounds.width);
+		setHeight(bounds.height);
+	}
+
 	Rect2I GUIElementBase::getGlobalBounds()
 	{
 		if (mUpdateParent != nullptr && mUpdateParent->_isDirty() && mParentWidget != nullptr)