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

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

Marko Pintera 12 лет назад
Родитель
Сommit
249b21533c

+ 4 - 0
BansheeEngine/Include/BsGUIDropDownBox.h

@@ -172,6 +172,10 @@ namespace BansheeEngine
 
 		DropDownSubMenu* mRootMenu;
 		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;
 

+ 6 - 3
BansheeEngine/Include/BsGUIDropDownHitBox.h

@@ -10,20 +10,23 @@ namespace BansheeEngine
 	public:
 		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; }
 
 		boost::signal<void()> onFocusLost;
 		boost::signal<void()> onFocusGained;
 
 	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 mouseEvent(const GUIMouseEvent& ev);
 		virtual bool _isInBounds(const CM::Vector2I position) const;
 
 		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)
 		:GUIWidget(parent, target), mScrollUpStyle(nullptr), mRootMenu(nullptr),
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
-		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mHitBox(nullptr)
+		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mHitBox(nullptr), mCaptureHitBox(nullptr)
 	{
 		String stylePrefix = "";
 		switch(type)
@@ -108,9 +108,16 @@ namespace BansheeEngine
 
 		mLocalizedEntryNames = dropDownData.localizedNames;
 
-		mHitBox = GUIDropDownHitBox::create(*this);
+		mHitBox = GUIDropDownHitBox::create(*this, false);
 		mHitBox->onFocusLost.connect(boost::bind(&GUIDropDownBox::dropDownFocusLost, this));
 		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());
 		mRootMenu = cm_new<DropDownSubMenu>(this, placement, availableBounds, dropDownData, type, 0);
@@ -119,6 +126,7 @@ namespace BansheeEngine
 	GUIDropDownBox::~GUIDropDownBox()
 	{
 		GUIElement::destroy(mHitBox);
+		GUIElement::destroy(mCaptureHitBox);
 		cm_delete(mRootMenu);
 	}
 
@@ -257,12 +265,12 @@ namespace BansheeEngine
 
 		// Content area
 		mContentArea = GUIArea::create(*mOwner, x, actualY, width, height);
-		mContentArea->setDepth(10000 - depthOffset * 2 - 1);
+		mContentArea->setDepth(100 - depthOffset * 2 - 1);
 		mContentLayout = &mContentArea->getLayout().addLayoutY();
 
 		// Background frame
 		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);
 		mBackgroundArea->getLayout().addElement(mBackgroundFrame);

+ 26 - 6
BansheeEngine/Source/BsGUIDropDownHitBox.cpp

@@ -1,5 +1,6 @@
 #include "BsGUIDropDownHitBox.h"
 #include "BsGUICommandEvent.h"
+#include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
 
@@ -13,7 +14,7 @@ namespace BansheeEngine
 		return name;
 	}
 
-	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, const GUIElementStyle* style)
+	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, bool captureMouse, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -21,10 +22,10 @@ namespace BansheeEngine
 			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)
 		{
@@ -32,11 +33,11 @@ namespace BansheeEngine
 			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;
 	}
 
+	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
 	{
 		for(auto& bound : mBounds)