Просмотр исходного кода

Don't block mouse clicks outside of drop down window/menu

Marko Pintera 10 лет назад
Родитель
Сommit
1bb0da2c8a

+ 2 - 1
BansheeEditor/Include/BsDropDownWindow.h

@@ -74,7 +74,8 @@ namespace BansheeEngine
 		HSceneObject mSceneObject;
 		HGUIWidget mGUI;
 
-		GUIDropDownHitBox* mHitBox;
+		GUIDropDownHitBox* mFrontHitBox;
+		GUIDropDownHitBox* mBackHitBox;
 		GUIPanel* mRootPanel;
 		Vector2I mPosition;
 		UINT32 mWidth;

+ 14 - 10
BansheeEditor/Source/BsDropDownWindow.cpp

@@ -14,7 +14,7 @@ namespace BansheeEngine
 	DropDownWindow::DropDownWindow(const RenderWindowPtr& parent, Viewport* target, 
 		const Vector2I& position, UINT32 width, UINT32 height)
 		:mRootPanel(nullptr), mPosition(position), mWidth(width), mHeight(height), 
-		mRenderWindow(parent), mHitBox(nullptr)
+		mRenderWindow(parent), mFrontHitBox(nullptr), mBackHitBox(nullptr)
 	{
 		mSceneObject = SceneObject::create("EditorWindow");
 
@@ -25,15 +25,18 @@ namespace BansheeEngine
 
 		mRootPanel = mGUI->getPanel()->addNewElement<GUIPanel>();
 		
-		GUIPanel* hitBoxPanel = mRootPanel->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min());
-
-		mHitBox = GUIDropDownHitBox::create(false);
-		mHitBox->onFocusLost.connect(std::bind(&DropDownWindow::dropDownFocusLost, this));
-		mHitBox->setFocus(true);
-		hitBoxPanel->addElement(mHitBox);
-
+		GUIPanel* frontHitBoxPanel = mRootPanel->addNewElement<GUIPanel>(std::numeric_limits<INT16>::min());
+		mFrontHitBox = GUIDropDownHitBox::create(false, false);
+		mFrontHitBox->onFocusLost.connect(std::bind(&DropDownWindow::dropDownFocusLost, this));
+		mFrontHitBox->setFocus(true);
+		frontHitBoxPanel->addElement(mFrontHitBox);
+
+		GUIPanel* backHitBoxPanel = mRootPanel->addNewElement<GUIPanel>(std::numeric_limits<INT16>::max());
+		mBackHitBox = GUIDropDownHitBox::create(false, true);
+		backHitBoxPanel->addElement(mBackHitBox);
+		
 		GUIPanel* captureHitBoxPanel = mGUI->getPanel()->addNewElement<GUIPanel>(std::numeric_limits<INT16>::max());
-		GUIDropDownHitBox* captureHitBox = GUIDropDownHitBox::create(true);
+		GUIDropDownHitBox* captureHitBox = GUIDropDownHitBox::create(true, false);
 		captureHitBox->setBounds(Rect2I(0, 0, target->getWidth(), target->getHeight()));
 		captureHitBoxPanel->addElement(captureHitBox);
 
@@ -96,7 +99,8 @@ namespace BansheeEngine
 		mRootPanel->setWidth(width);
 		mRootPanel->setHeight(height);
 
-		mHitBox->setBounds(Rect2I(placementBounds.x, placementBounds.y, width, height));
+		mFrontHitBox->setBounds(Rect2I(placementBounds.x, placementBounds.y, width, height));
+		mBackHitBox->setBounds(Rect2I(placementBounds.x, placementBounds.y, width, height));
 
 		mWidth = width;
 		mHeight = height;

+ 13 - 10
BansheeEngine/Include/BsGUIDropDownHitBox.h

@@ -21,21 +21,23 @@ namespace BansheeEngine
 		 * Creates a new drop down hit box that will detect mouse input over certain area.
 		 * You must call "setBounds" to define the area.
 		 *
-		 * @param	captureMouse	If true mouse clicks will be captured by this control and wont be passed
-		 *							to other GUI elements.
+		 * @param	captureMouseOver	If true mouse over/out/move events will be captured by this control 
+		 *								and wont be passed to other GUI elements.
+		 * @param	captureMousePresses	If true mouse clicks will be captured by this control and wont be passed
+		 *								to other GUI elements.
 		 */
-		static GUIDropDownHitBox* create(bool captureMouse);
+		static GUIDropDownHitBox* create(bool captureMouseOver, bool captureMousePresses);
 
 		/**
 		 * Creates a new drop down hit box that will detect mouse input over certain area.
 		 * You must call "setBounds" to define the area.
 		 *
-		 * @param	captureMouse	If true mouse clicks will be captured by this control and wont be passed
-		 *							to other GUI elements.
-		 * @param	options			Options that allow you to control how is the element positioned and sized.
-		 *							This will override any similar options set by style.
+		 * @param	captureMouseOver	If true mouse over/out/move events will be captured by this control
+		 *								and wont be passed to other GUI elements.
+		 * @param	captureMousePresses	If true mouse clicks will be captured by this control and wont be passed
+		 *								to other GUI elements.
 		 */
-		static GUIDropDownHitBox* create(bool captureMouse, const GUIOptions& options);
+		static GUIDropDownHitBox* create(bool captureMouseOver, bool captureMousePresses, const GUIOptions& options);
 
 		/**
 		 * Sets a single rectangle bounds in which the hitbox will capture mouse events.
@@ -58,7 +60,7 @@ namespace BansheeEngine
 		Event<void()> onFocusGained;
 
 	private:
-		GUIDropDownHitBox(bool captureMouse, const GUIDimensions& dimensions);
+		GUIDropDownHitBox(bool captureMouseOver, bool captureMousePresses, const GUIDimensions& dimensions);
 
 		/**
 		 * @copydoc	GUIElementContainer::updateClippedBounds
@@ -70,6 +72,7 @@ namespace BansheeEngine
 		virtual bool _isInBounds(const Vector2I position) const;
 
 		Vector<Rect2I> mBounds;
-		bool mCaptureMouse;
+		bool mCaptureMouseOver;
+		bool mCaptureMousePresses;
 	};
 }

+ 3 - 1
BansheeEngine/Include/BsGUIDropDownMenu.h

@@ -277,7 +277,9 @@ namespace BansheeEngine
 		HSpriteTexture mScrollDownBtnArrow;
 
 		DropDownSubMenu* mRootMenu;
-		GUIDropDownHitBox* mHitBox;
+		GUIDropDownHitBox* mFrontHitBox;
+		GUIDropDownHitBox* mBackHitBox;
+
 		// Captures mouse clicks so that we don't trigger elements outside the drop down box when we just want to close it.
 		// (Particular example is clicking on the button that opened the drop down box in the first place. Clicking will cause
 		// the drop down to lose focus and close, but if the button still processes the mouse click it will be immediately opened again)

+ 20 - 12
BansheeEngine/Source/BsGUIDropDownHitBox.cpp

@@ -12,18 +12,22 @@ namespace BansheeEngine
 		return name;
 	}
 
-	GUIDropDownHitBox* GUIDropDownHitBox::create(bool captureMouse)
+	GUIDropDownHitBox* GUIDropDownHitBox::create(bool captureMouseOver, bool captureMousePresses)
 	{
-		return new (bs_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(captureMouse, GUIDimensions::create());
+		return new (bs_alloc<GUIDropDownHitBox, PoolAlloc>()) 
+			GUIDropDownHitBox(captureMouseOver, captureMousePresses, GUIDimensions::create());
 	}
 
-	GUIDropDownHitBox* GUIDropDownHitBox::create(bool captureMouse, const GUIOptions& options)
+	GUIDropDownHitBox* GUIDropDownHitBox::create(bool captureMouseOver, bool captureMousePresses, const GUIOptions& options)
 	{
-		return new (bs_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(captureMouse, GUIDimensions::create(options));
+		return new (bs_alloc<GUIDropDownHitBox, PoolAlloc>()) 
+			GUIDropDownHitBox(captureMouseOver, captureMousePresses, GUIDimensions::create(options));
 	}
 
-	GUIDropDownHitBox::GUIDropDownHitBox(bool captureMouse, const GUIDimensions& dimensions)
-		:GUIElementContainer(dimensions), mCaptureMouse(captureMouse)
+	GUIDropDownHitBox::GUIDropDownHitBox(bool captureMouseOver, 
+		bool captureMousePresses, const GUIDimensions& dimensions)
+		:GUIElementContainer(dimensions), mCaptureMouseOver(captureMouseOver),
+		mCaptureMousePresses(captureMousePresses)
 	{
 
 	}
@@ -82,25 +86,29 @@ namespace BansheeEngine
 	{
 		bool processed = GUIElementContainer::_mouseEvent(ev);
 
-		if(mCaptureMouse)
+		if(mCaptureMouseOver)
 		{
-			if(ev.getType() == GUIMouseEventType::MouseUp)
+			if (ev.getType() == GUIMouseEventType::MouseOver)
 			{
 				return true;
 			}
-			else if(ev.getType() == GUIMouseEventType::MouseDown)
+			else if (ev.getType() == GUIMouseEventType::MouseOut)
 			{
 				return true;
 			}
-			else if (ev.getType() == GUIMouseEventType::MouseOver)
+			else if (ev.getType() == GUIMouseEventType::MouseMove)
 			{
 				return true;
 			}
-			else if (ev.getType() == GUIMouseEventType::MouseOut)
+		}
+
+		if (mCaptureMousePresses)
+		{
+			if (ev.getType() == GUIMouseEventType::MouseUp)
 			{
 				return true;
 			}
-			else if (ev.getType() == GUIMouseEventType::MouseMove)
+			else if (ev.getType() == GUIMouseEventType::MouseDown)
 			{
 				return true;
 			}

+ 26 - 15
BansheeEngine/Source/BsGUIDropDownMenu.cpp

@@ -54,7 +54,7 @@ namespace BansheeEngine
 
 	GUIDropDownMenu::GUIDropDownMenu(const HSceneObject& parent, Viewport* target, const DropDownAreaPlacement& placement,
 		const GUIDropDownData& dropDownData, const HGUISkin& skin, GUIDropDownType type)
-		:GUIWidget(parent, target), mRootMenu(nullptr), mHitBox(nullptr), mCaptureHitBox(nullptr)
+		:GUIWidget(parent, target), mRootMenu(nullptr), mFrontHitBox(nullptr), mCaptureHitBox(nullptr), mBackHitBox(nullptr)
 	{
 		String stylePrefix = "";
 		switch(type)
@@ -81,21 +81,29 @@ namespace BansheeEngine
 		setDepth(0); // Needs to be in front of everything
 		setSkin(skin);
 
-		mHitBox = GUIDropDownHitBox::create(false);
-		mHitBox->onFocusLost.connect(std::bind(&GUIDropDownMenu::dropDownFocusLost, this));
-		mHitBox->setFocus(true);
-		GUILayoutData hitboxLayoutData = mHitBox->_getLayoutData();
+		mFrontHitBox = GUIDropDownHitBox::create(false, false);
+		mFrontHitBox->onFocusLost.connect(std::bind(&GUIDropDownMenu::dropDownFocusLost, this));
+		mFrontHitBox->setFocus(true);
+		GUILayoutData hitboxLayoutData = mFrontHitBox->_getLayoutData();
 		hitboxLayoutData.setWidgetDepth(0);
-		hitboxLayoutData.setPanelDepth(0);
-		mHitBox->_setLayoutData(hitboxLayoutData);
-		mHitBox->_changeParentWidget(this);
-		mHitBox->_markContentAsDirty();
-
-		mCaptureHitBox = GUIDropDownHitBox::create(true);
+		hitboxLayoutData.setPanelDepth(std::numeric_limits<INT16>::min());
+		mFrontHitBox->_setLayoutData(hitboxLayoutData);
+		mFrontHitBox->_changeParentWidget(this);
+		mFrontHitBox->_markContentAsDirty();
+
+		mBackHitBox = GUIDropDownHitBox::create(false, true);
+		GUILayoutData backHitboxLayoutData = mBackHitBox->_getLayoutData();
+		backHitboxLayoutData.setWidgetDepth(0);
+		backHitboxLayoutData.setPanelDepth(std::numeric_limits<INT16>::max());
+		mBackHitBox->_setLayoutData(hitboxLayoutData);
+		mBackHitBox->_changeParentWidget(this);
+		mBackHitBox->_markContentAsDirty();
+
+		mCaptureHitBox = GUIDropDownHitBox::create(true, false);
 		mCaptureHitBox->setBounds(Rect2I(0, 0, target->getWidth(), target->getHeight()));
 		GUILayoutData captureHitboxLayoutData = mCaptureHitBox->_getLayoutData();
 		captureHitboxLayoutData.setWidgetDepth(0);
-		captureHitboxLayoutData.setPanelDepth(200);
+		captureHitboxLayoutData.setPanelDepth(std::numeric_limits<INT16>::max());
 		mCaptureHitBox->_setLayoutData(captureHitboxLayoutData);
 		mCaptureHitBox->_changeParentWidget(this);
 		mCaptureHitBox->_markContentAsDirty();
@@ -111,7 +119,8 @@ namespace BansheeEngine
 
 	void GUIDropDownMenu::onDestroyed()
 	{
-		GUIElement::destroy(mHitBox);
+		GUIElement::destroy(mFrontHitBox);
+		GUIElement::destroy(mBackHitBox);
 		GUIElement::destroy(mCaptureHitBox);
 		bs_delete(mRootMenu);
 
@@ -135,7 +144,8 @@ namespace BansheeEngine
 			subMenu = subMenu->mSubMenu;
 		}
 
-		mHitBox->setBounds(bounds);
+		mFrontHitBox->setBounds(bounds);
+		mBackHitBox->setBounds(bounds);
 	}
 
 	void GUIDropDownMenu::notifySubMenuClosed(DropDownSubMenu* subMenu)
@@ -149,7 +159,8 @@ namespace BansheeEngine
 			subMenu = subMenu->mSubMenu;
 		}
 
-		mHitBox->setBounds(bounds);
+		mFrontHitBox->setBounds(bounds);
+		mBackHitBox->setBounds(bounds);
 	}
 
 	GUIDropDownMenu::DropDownSubMenu::DropDownSubMenu(GUIDropDownMenu* owner, DropDownSubMenu* parent, const DropDownAreaPlacement& placement,