Browse Source

DropDownBox now captures all mouse clicks outside of it, so we don't trigger the buttons when trying to close it

Marko Pintera 12 years ago
parent
commit
249b21533c

+ 4 - 0
BansheeEngine/Include/BsGUIDropDownBox.h

@@ -172,6 +172,10 @@ namespace BansheeEngine
 
 
 		DropDownSubMenu* mRootMenu;
 		DropDownSubMenu* mRootMenu;
 		GUIDropDownHitBox* mHitBox;
 		GUIDropDownHitBox* mHitBox;
+		// 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)
+		GUIDropDownHitBox* mCaptureHitBox; 
 
 
 		CM::UnorderedMap<CM::WString, CM::HString>::type mLocalizedEntryNames;
 		CM::UnorderedMap<CM::WString, CM::HString>::type mLocalizedEntryNames;
 
 

+ 6 - 3
BansheeEngine/Include/BsGUIDropDownHitBox.h

@@ -10,20 +10,23 @@ namespace BansheeEngine
 	public:
 	public:
 		static const CM::String& getGUITypeName();
 		static const CM::String& getGUITypeName();
 
 
-		static GUIDropDownHitBox* create(GUIWidget& parent, const GUIElementStyle* style = nullptr);
-		static GUIDropDownHitBox* create(GUIWidget& parent, const GUIOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+		static GUIDropDownHitBox* create(GUIWidget& parent, bool captureMouse, const GUIElementStyle* style = nullptr);
+		static GUIDropDownHitBox* create(GUIWidget& parent, bool captureMouse, const GUIOptions& layoutOptions, const GUIElementStyle* style = nullptr);
 
 
+		void setBounds(const CM::RectI& bounds) { mBounds.clear(); mBounds.push_back(bounds); }
 		void setBounds(const CM::Vector<CM::RectI>::type& bounds) { mBounds = bounds; }
 		void setBounds(const CM::Vector<CM::RectI>::type& bounds) { mBounds = bounds; }
 
 
 		boost::signal<void()> onFocusLost;
 		boost::signal<void()> onFocusLost;
 		boost::signal<void()> onFocusGained;
 		boost::signal<void()> onFocusGained;
 
 
 	private:
 	private:
-		GUIDropDownHitBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
+		GUIDropDownHitBox(GUIWidget& parent, bool captureMouse, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
 
 
 		virtual bool commandEvent(const GUICommandEvent& ev);
 		virtual bool commandEvent(const GUICommandEvent& ev);
+		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool _isInBounds(const CM::Vector2I position) const;
 		virtual bool _isInBounds(const CM::Vector2I position) const;
 
 
 		CM::Vector<CM::RectI>::type mBounds;
 		CM::Vector<CM::RectI>::type mBounds;
+		bool mCaptureMouse;
 	};
 	};
 }
 }

+ 12 - 4
BansheeEngine/Source/BsGUIDropDownBox.cpp

@@ -77,7 +77,7 @@ namespace BansheeEngine
 		const GUIDropDownData& dropDownData, const GUISkin& skin, GUIDropDownType type)
 		const GUIDropDownData& dropDownData, const GUISkin& skin, GUIDropDownType type)
 		:GUIWidget(parent, target), mScrollUpStyle(nullptr), mRootMenu(nullptr),
 		:GUIWidget(parent, target), mScrollUpStyle(nullptr), mRootMenu(nullptr),
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
-		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mHitBox(nullptr)
+		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mHitBox(nullptr), mCaptureHitBox(nullptr)
 	{
 	{
 		String stylePrefix = "";
 		String stylePrefix = "";
 		switch(type)
 		switch(type)
@@ -108,9 +108,16 @@ namespace BansheeEngine
 
 
 		mLocalizedEntryNames = dropDownData.localizedNames;
 		mLocalizedEntryNames = dropDownData.localizedNames;
 
 
-		mHitBox = GUIDropDownHitBox::create(*this);
+		mHitBox = GUIDropDownHitBox::create(*this, false);
 		mHitBox->onFocusLost.connect(boost::bind(&GUIDropDownBox::dropDownFocusLost, this));
 		mHitBox->onFocusLost.connect(boost::bind(&GUIDropDownBox::dropDownFocusLost, this));
 		mHitBox->setFocus(true);
 		mHitBox->setFocus(true);
+		mHitBox->_setWidgetDepth(0);
+		mHitBox->_setAreaDepth(0);
+
+		mCaptureHitBox = GUIDropDownHitBox::create(*this, true);
+		mCaptureHitBox->setBounds(RectI(0, 0, target->getWidth(), target->getHeight()));
+		mCaptureHitBox->_setWidgetDepth(0);
+		mCaptureHitBox->_setAreaDepth(200);
 
 
 		RectI availableBounds(target->getX(), target->getY(), target->getWidth(), target->getHeight());
 		RectI availableBounds(target->getX(), target->getY(), target->getWidth(), target->getHeight());
 		mRootMenu = cm_new<DropDownSubMenu>(this, placement, availableBounds, dropDownData, type, 0);
 		mRootMenu = cm_new<DropDownSubMenu>(this, placement, availableBounds, dropDownData, type, 0);
@@ -119,6 +126,7 @@ namespace BansheeEngine
 	GUIDropDownBox::~GUIDropDownBox()
 	GUIDropDownBox::~GUIDropDownBox()
 	{
 	{
 		GUIElement::destroy(mHitBox);
 		GUIElement::destroy(mHitBox);
+		GUIElement::destroy(mCaptureHitBox);
 		cm_delete(mRootMenu);
 		cm_delete(mRootMenu);
 	}
 	}
 
 
@@ -257,12 +265,12 @@ namespace BansheeEngine
 
 
 		// Content area
 		// Content area
 		mContentArea = GUIArea::create(*mOwner, x, actualY, width, height);
 		mContentArea = GUIArea::create(*mOwner, x, actualY, width, height);
-		mContentArea->setDepth(10000 - depthOffset * 2 - 1);
+		mContentArea->setDepth(100 - depthOffset * 2 - 1);
 		mContentLayout = &mContentArea->getLayout().addLayoutY();
 		mContentLayout = &mContentArea->getLayout().addLayoutY();
 
 
 		// Background frame
 		// Background frame
 		mBackgroundArea = GUIArea::create(*mOwner, x, actualY, width, height);
 		mBackgroundArea = GUIArea::create(*mOwner, x, actualY, width, height);
-		mBackgroundArea->setDepth(10000 - depthOffset * 2);
+		mBackgroundArea->setDepth(100 - depthOffset * 2);
 
 
 		mBackgroundFrame = GUITexture::create(*mOwner, GUIImageScaleMode::StretchToFit, mOwner->mBackgroundStyle);
 		mBackgroundFrame = GUITexture::create(*mOwner, GUIImageScaleMode::StretchToFit, mOwner->mBackgroundStyle);
 		mBackgroundArea->getLayout().addElement(mBackgroundFrame);
 		mBackgroundArea->getLayout().addElement(mBackgroundFrame);

+ 26 - 6
BansheeEngine/Source/BsGUIDropDownHitBox.cpp

@@ -1,5 +1,6 @@
 #include "BsGUIDropDownHitBox.h"
 #include "BsGUIDropDownHitBox.h"
 #include "BsGUICommandEvent.h"
 #include "BsGUICommandEvent.h"
+#include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 
 
@@ -13,7 +14,7 @@ namespace BansheeEngine
 		return name;
 		return name;
 	}
 	}
 
 
-	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, const GUIElementStyle* style)
+	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, bool captureMouse, const GUIElementStyle* style)
 	{
 	{
 		if(style == nullptr)
 		if(style == nullptr)
 		{
 		{
@@ -21,10 +22,10 @@ namespace BansheeEngine
 			style = skin.getStyle(getGUITypeName());
 			style = skin.getStyle(getGUITypeName());
 		}
 		}
 
 
-		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, style, GUILayoutOptions::create(style));
+		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, captureMouse, style, GUILayoutOptions::create(style));
 	}
 	}
 
 
-	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, const GUIOptions& layoutOptions, const GUIElementStyle* style)
+	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, bool captureMouse, const GUIOptions& layoutOptions, const GUIElementStyle* style)
 	{
 	{
 		if(style == nullptr)
 		if(style == nullptr)
 		{
 		{
@@ -32,11 +33,11 @@ namespace BansheeEngine
 			style = skin.getStyle(getGUITypeName());
 			style = skin.getStyle(getGUITypeName());
 		}
 		}
 
 
-		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, style, GUILayoutOptions::create(layoutOptions, style));
+		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, captureMouse, style, GUILayoutOptions::create(layoutOptions, style));
 	}
 	}
 
 
-	GUIDropDownHitBox::GUIDropDownHitBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(parent, layoutOptions)
+	GUIDropDownHitBox::GUIDropDownHitBox(GUIWidget& parent, bool captureMouse, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(parent, layoutOptions), mCaptureMouse(captureMouse)
 	{
 	{
 
 
 	}
 	}
@@ -63,6 +64,25 @@ namespace BansheeEngine
 		return processed;
 		return processed;
 	}
 	}
 
 
+	bool GUIDropDownHitBox::mouseEvent(const GUIMouseEvent& ev)
+	{
+		bool processed = GUIElementContainer::mouseEvent(ev);
+
+		if(mCaptureMouse)
+		{
+			if(ev.getType() == GUIMouseEventType::MouseUp)
+			{
+				return true;
+			}
+			else if(ev.getType() == GUIMouseEventType::MouseDown)
+			{
+				return true;
+			}
+		}
+
+		return processed;
+	}
+
 	bool GUIDropDownHitBox::_isInBounds(const CM::Vector2I position) const
 	bool GUIDropDownHitBox::_isInBounds(const CM::Vector2I position) const
 	{
 	{
 		for(auto& bound : mBounds)
 		for(auto& bound : mBounds)