Selaa lähdekoodia

Added better handling for different positioning types GUIDropDownBox needs

Marko Pintera 12 vuotta sitten
vanhempi
sitoutus
8ac654905c

+ 54 - 2
BansheeEngine/Include/BsGUIDropDownBox.h

@@ -1,5 +1,6 @@
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
+#include "CmInt2.h"
 #include <boost/signal.hpp>
 #include <boost/signal.hpp>
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -33,6 +34,57 @@ namespace BansheeEngine
 		Type mType; 
 		Type mType; 
 	};
 	};
 
 
+	/**
+	 * @brief	Determines how will the drop down box be placed. Usually the system will attempt to position
+	 * 			the drop box in a way so all elements can fit, and this class allows you to specify some limitations
+	 * 			on how that works. 
+	 * 			
+	 * @note	For example, list boxes usually want drop down boxes to be placed above or below them, while
+	 * 			context menus may want to have them placed around a single point in any direction.
+	 */
+	class BS_EXPORT GUIDropDownAreaPlacement
+	{
+	public:
+		enum class Type
+		{
+			Position,
+			BoundsVert,
+			BoundsHorz
+		};
+
+		/**
+		 * @brief	Drop down box will be placed at the specified position. By default the system
+		 * 			prefers the top left corner of the box to correspond to the position, but if
+		 * 			other corners offer more space for the contents, those will be used instead.
+		 */
+		static GUIDropDownAreaPlacement aroundPosition(const CM::Int2& position);
+
+		/**
+		 * @brief	Drop down box will be placed at the specified bounds. Box will be horizontally aligned to the left
+		 * 			of the provided bounds. Vertically system prefers placing the box at the bottom of the bounds, but may choose
+		 * 			to align it with the top of the bounds if it offers more space for the contents.
+		 */
+		static GUIDropDownAreaPlacement aroundBoundsVert(const CM::Rect& bounds);
+		
+		/**
+		 * @brief	Drop down box will be placed at the specified bounds. Box will be vertically aligned to the top
+		 * 			of the provided bounds. Horizontally system prefers placing the box at the right of the bounds, but may choose
+		 * 			to align it with the left of the bounds if it offers more space for the contents.
+		 */
+		static GUIDropDownAreaPlacement aroundBoundsHorz(const CM::Rect& bounds);
+
+		Type getType() const { return mType; }
+		const CM::Rect& getBounds() const { return mBounds; }
+		const CM::Int2& getPosition() const { return mPosition; }
+
+	private:
+		GUIDropDownAreaPlacement() { }
+
+		Type mType;
+		CM::Rect mBounds;
+		CM::Int2 mPosition;
+	};
+
 	enum class GUIDropDownType
 	enum class GUIDropDownType
 	{
 	{
 		ListBox,
 		ListBox,
@@ -50,7 +102,7 @@ namespace BansheeEngine
 		GUIDropDownBox(const CM::HSceneObject& parent);
 		GUIDropDownBox(const CM::HSceneObject& parent);
 		~GUIDropDownBox();
 		~GUIDropDownBox();
 
 
-		void initialize(CM::Viewport* target, CM::RenderWindow* window, GUIElement* parentElem,
+		void initialize(CM::Viewport* target, CM::RenderWindow* window, const GUIDropDownAreaPlacement& placement,
 			const CM::Vector<GUIDropDownData>::type& elements, const GUISkin& skin, GUIDropDownType type);
 			const CM::Vector<GUIDropDownData>::type& elements, const GUISkin& skin, GUIDropDownType type);
 	private:
 	private:
 		static const CM::UINT32 DROP_DOWN_BOX_WIDTH;
 		static const CM::UINT32 DROP_DOWN_BOX_WIDTH;
@@ -92,7 +144,7 @@ namespace BansheeEngine
 		CM::UINT32 getElementHeight(CM::UINT32 idx) const;
 		CM::UINT32 getElementHeight(CM::UINT32 idx) const;
 
 
 		void elementClicked(CM::UINT32 idx);
 		void elementClicked(CM::UINT32 idx);
-		void openSubMenu(CM::UINT32 elementIdx);
+		void openSubMenu(GUIButton* source, CM::UINT32 elementIdx);
 		void closeSubMenu();
 		void closeSubMenu();
 	};
 	};
 }
 }

+ 33 - 6
BansheeEngine/Source/BsGUIDropDownBox.cpp

@@ -44,6 +44,33 @@ namespace BansheeEngine
 		return data;
 		return data;
 	}
 	}
 
 
+	GUIDropDownAreaPlacement GUIDropDownAreaPlacement::aroundPosition(const CM::Int2& position)
+	{
+		GUIDropDownAreaPlacement instance;
+		instance.mType = Type::Position;
+		instance.mPosition = position;
+
+		return instance;
+	}
+
+	GUIDropDownAreaPlacement GUIDropDownAreaPlacement::aroundBoundsVert(const CM::Rect& bounds)
+	{
+		GUIDropDownAreaPlacement instance;
+		instance.mType = Type::BoundsVert;
+		instance.mBounds = bounds;
+
+		return instance;
+	}
+		
+	GUIDropDownAreaPlacement GUIDropDownAreaPlacement::aroundBoundsHorz(const CM::Rect& bounds)
+	{
+		GUIDropDownAreaPlacement instance;
+		instance.mType = Type::BoundsHorz;
+		instance.mBounds = bounds;
+
+		return instance;
+	}
+
 	GUIDropDownBox::GUIDropDownBox(const HSceneObject& parent)
 	GUIDropDownBox::GUIDropDownBox(const HSceneObject& parent)
 		:GUIWidget(parent), mPage(0), mBackgroundFrame(nullptr), mScrollUpStyle(nullptr),
 		:GUIWidget(parent), mPage(0), mBackgroundFrame(nullptr), mScrollUpStyle(nullptr),
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
@@ -59,7 +86,7 @@ namespace BansheeEngine
 		closeSubMenu();
 		closeSubMenu();
 	}
 	}
 
 
-	void GUIDropDownBox::initialize(Viewport* target, RenderWindow* window, GUIElement* parentElem, 
+	void GUIDropDownBox::initialize(Viewport* target, RenderWindow* window, const GUIDropDownAreaPlacement& placement, 
 		const CM::Vector<GUIDropDownData>::type& elements, const GUISkin& skin, GUIDropDownType type)
 		const CM::Vector<GUIDropDownData>::type& elements, const GUISkin& skin, GUIDropDownType type)
 	{
 	{
 		GUIWidget::initialize(target, window);
 		GUIWidget::initialize(target, window);
@@ -94,7 +121,7 @@ namespace BansheeEngine
 		setDepth(0); // Needs to be in front of everything
 		setDepth(0); // Needs to be in front of everything
 		setSkin(skin);
 		setSkin(skin);
 
 
-		Rect dropDownListBounds = parentElem->getBounds();
+		Rect dropDownListBounds = placement.getBounds();
 
 
 		// Determine x position and whether to align to left or right side of the drop down list
 		// Determine x position and whether to align to left or right side of the drop down list
 		UINT32 availableRightwardWidth = (UINT32)std::max(0, (target->getLeft() + target->getWidth()) - dropDownListBounds.x);
 		UINT32 availableRightwardWidth = (UINT32)std::max(0, (target->getLeft() + target->getWidth()) - dropDownListBounds.x);
@@ -263,7 +290,7 @@ namespace BansheeEngine
 				else
 				else
 				{
 				{
 					expEntryBtn = GUIButton::create(*this, mElements[i].getLabel(), mEntryExpBtnStyle);
 					expEntryBtn = GUIButton::create(*this, mElements[i].getLabel(), mEntryExpBtnStyle);
-					expEntryBtn->onHover.connect(boost::bind(&GUIDropDownBox::openSubMenu, this, i));
+					expEntryBtn->onHover.connect(boost::bind(&GUIDropDownBox::openSubMenu, this, expEntryBtn, i));
 				}
 				}
 
 
 				mContentLayout->addElement(expEntryBtn);
 				mContentLayout->addElement(expEntryBtn);
@@ -378,14 +405,14 @@ namespace BansheeEngine
 		mElements[idx].getCallback()();
 		mElements[idx].getCallback()();
 	}
 	}
 
 
-	void GUIDropDownBox::openSubMenu(UINT32 idx)
+	void GUIDropDownBox::openSubMenu(GUIButton* source, UINT32 idx)
 	{
 	{
 		closeSubMenu();
 		closeSubMenu();
 
 
 		mSubMenuSO = SceneObject::create("DropDownBox");
 		mSubMenuSO = SceneObject::create("DropDownBox");
 		mSubMenuDropDownBox = mSubMenuSO->addComponent<GUIDropDownBox>();
 		mSubMenuDropDownBox = mSubMenuSO->addComponent<GUIDropDownBox>();
 
 
-		// TODO - Need to provide a parent element
-		mSubMenuDropDownBox->initialize(getTarget(), getOwnerWindow(), nullptr, mElements[idx].getSubMenuEntries(), getSkin(), mType);
+		mSubMenuDropDownBox->initialize(getTarget(), getOwnerWindow(), 
+			GUIDropDownAreaPlacement::aroundBoundsVert(source->getBounds()), mElements[idx].getSubMenuEntries(), getSkin(), mType);
 	}
 	}
 }
 }

+ 4 - 2
BansheeEngine/Source/BsGUIManager.cpp

@@ -521,7 +521,8 @@ namespace BansheeEngine
 			i++;
 			i++;
 		}
 		}
 
 
-		mDropDownBox->initialize(widget.getTarget(), widget.getOwnerWindow(), parentList, dropDownData, skin, GUIDropDownType::ListBox);
+		mDropDownBox->initialize(widget.getTarget(), widget.getOwnerWindow(), 
+			GUIDropDownAreaPlacement::aroundBoundsHorz(parentList->getBounds()), dropDownData, skin, GUIDropDownType::ListBox);
 
 
 		mDropDownBoxOpenScheduled = true;
 		mDropDownBoxOpenScheduled = true;
 		mListBoxSelectionMade = selectedCallback;
 		mListBoxSelectionMade = selectedCallback;
@@ -552,7 +553,8 @@ namespace BansheeEngine
 
 
 		//Vector<GUIDropDownData>::type dropDownData = menu->getDropDownData();
 		//Vector<GUIDropDownData>::type dropDownData = menu->getDropDownData();
 
 
-		//mDropDownBox->initialize(widget.getTarget(), widget.getOwnerWindow(), parentList, dropDownData, widget.getSkin(), GUIDropDownType::ContextMenu);
+		//mDropDownBox->initialize(widget.getTarget(), widget.getOwnerWindow(), 
+		//	GUIDropDownAreaPlacement::aroundPosition(position), dropDownData, widget.getSkin(), GUIDropDownType::ContextMenu);
 
 
 		mDropDownBoxOpenScheduled = true;
 		mDropDownBoxOpenScheduled = true;
 	}
 	}

+ 3 - 4
DropDown.txt

@@ -2,11 +2,10 @@ GUI ignores image in GUIContent for most elements.
 
 
 Doesn't belong here but as an additional reminder: Remove Component::initialize and instead make multi paramter addComponent
 Doesn't belong here but as an additional reminder: Remove Component::initialize and instead make multi paramter addComponent
 
 
-GUIDropDownBox::openSubMenu
- - I need to provide a parent element, also I probably need a way to distinguish between original drop down box, and sub-menu one
-
+GUIDropDownBox needs to properly handle different GUIDropDownPlacement types! Currently it just assumes BoundsHorz
 GUIContextMenu::getDropDownData needs to be implemented
 GUIContextMenu::getDropDownData needs to be implemented
-GUIDropDownBox only accepts a GUIElement, while GUIContextMenu only specifies a position
+
+ListBox: Clicking on ListBox once the DropDownBox is open should close the drop down box (I assume it does, it just re-opens it immediately again?)
 
 
 GUIMenuBar
 GUIMenuBar
  - It has a specific position, width and height
  - It has a specific position, width and height