Browse Source

Removed selective input
Updated DropDownBox so it uses lost/gained focus system instead of selective input
Added setFocus method to GUIElement

Marko Pintera 12 years ago
parent
commit
8e34ff6c59

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -241,6 +241,7 @@
     <ClInclude Include="Include\BsDebugDrawMaterialInfo.h" />
     <ClInclude Include="Include\BsGUIDropDownBox.h" />
     <ClInclude Include="Include\BsGUIDropDownBoxManager.h" />
+    <ClInclude Include="Include\BsGUIDropDownHitBox.h" />
     <ClInclude Include="Include\BsGUIElementContainer.h" />
     <ClInclude Include="Include\BsGUIHelper.h" />
     <ClInclude Include="Include\BsGUIListBox.h" />
@@ -311,6 +312,7 @@
     <ClCompile Include="Source\BsGUIContent.cpp" />
     <ClCompile Include="Source\BsGUIDropDownBox.cpp" />
     <ClCompile Include="Source\BsGUIDropDownBoxManager.cpp" />
+    <ClCompile Include="Source\BsGUIDropDownHitBox.cpp" />
     <ClCompile Include="Source\BsGUIElementContainer.cpp" />
     <ClCompile Include="Source\BsGUIHelper.cpp" />
     <ClCompile Include="Source\BsGUILayoutOptions.cpp" />

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -252,6 +252,9 @@
     <ClInclude Include="Include\BsGUIElementContainer.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIDropDownHitBox.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -437,5 +440,8 @@
     <ClCompile Include="Source\BsGUIElementContainer.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIDropDownHitBox.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 9 - 0
BansheeEngine/Include/BsGUIDropDownBox.h

@@ -121,6 +121,7 @@ namespace BansheeEngine
 			CM::UINT32 mPage;
 			CM::INT32 x, y;
 			CM::UINT32 width, height;
+			CM::RectI mVisibleBounds;
 			CM::RectI mAvailableBounds;
 			CM::UINT32 mDepthOffset;
 			bool mOpenedUpward;
@@ -153,6 +154,8 @@ namespace BansheeEngine
 			void openSubMenu(GUIButton* source, CM::UINT32 elementIdx);
 			void closeSubMenu();
 
+			CM::RectI getVisibleBounds() const { return mVisibleBounds; }
+
 			CM::HString getElementLocalizedName(CM::UINT32 idx) const;
 		};
 
@@ -168,7 +171,13 @@ namespace BansheeEngine
 		HSpriteTexture mScrollDownBtnArrow;
 
 		DropDownSubMenu* mRootMenu;
+		GUIDropDownHitBox* mHitBox;
 
 		CM::UnorderedMap<CM::WString, CM::HString>::type mLocalizedEntryNames;
+
+		void notifySubMenuOpened(DropDownSubMenu* subMenu);
+		void notifySubMenuClosed(DropDownSubMenu* subMenu);
+
+		void dropDownFocusLost();
 	};
 }

+ 29 - 0
BansheeEngine/Include/BsGUIDropDownHitBox.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElementContainer.h"
+
+namespace BansheeEngine
+{
+	class GUIDropDownHitBox : public GUIElementContainer
+	{
+	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);
+
+		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);
+
+		virtual bool commandEvent(const GUICommandEvent& ev);
+		virtual bool _isInBounds(const CM::Vector2I position) const;
+
+		CM::Vector<CM::RectI>::type mBounds;
+	};
+}

+ 5 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -79,6 +79,11 @@ namespace BansheeEngine
 		 */
 		CM::RectI getBounds() const;
 
+		/**
+		 * @brief	Sets or removes focus from an element.
+		 */
+		void setFocus(bool enabled);
+
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool textInputEvent(const GUITextInputEvent& ev);
 		virtual bool commandEvent(const GUICommandEvent& ev);

+ 20 - 23
BansheeEngine/Include/BsGUIManager.h

@@ -14,6 +14,16 @@ namespace BansheeEngine
 {
 	/**
 	 * @brief	Manages the rendering and input of all GUI widgets in the scene. 
+	 * 			
+	 * @note	If adding or modifying GUIManager functionality ensure that GUIManager data never gets modified
+	 * 			outside of update() method or Input callbacks. If you need such functionality add temporary variables
+	 * 			that store you changes and then execute them delayed in update().  
+	 * 			
+	 *			This ensures that GUIElements don't recursively modify GUIManager while GUIManager is still using that data.
+	 *			
+	 *			e.g. setFocus usually gets called from within GUIElements, however we don't want elements in focus be modified immediately 
+	 *			since that setFocus call could have originated in sendCommandEvent and elements in focus array would be modified while
+	 *			still being iterated upon.
 	 */
 	class BS_EXPORT GUIManager : public CM::Module<GUIManager>
 	{
@@ -56,6 +66,12 @@ namespace BansheeEngine
 			GUIWidget* widget;
 		};
 
+		struct ElementFocusInfo
+		{
+			GUIElement* element;
+			bool focus;
+		};
+
 	public:
 		GUIManager();
 		~GUIManager();
@@ -68,6 +84,8 @@ namespace BansheeEngine
 
 		void queueForDestroy(GUIElement* element);
 
+		void setFocus(GUIElement* element, bool focus);
+
 		void setCaretColor(const CM::Color& color) { mCaretColor = color; updateCaretTexture(); }
 		void setTextSelectionColor(const CM::Color& color) { mTextSelectionColor = color; updateTextSelectionTexture(); }
 		const HSpriteTexture& getCaretTexture() const { return mCaretTexture; }
@@ -77,24 +95,6 @@ namespace BansheeEngine
 		GUIInputCaret* getInputCaretTool() const { return mInputCaret; }
 		GUIInputSelection* getInputSelectionTool() const { return mInputSelection; }
 
-		/**
-		 * @brief	Selective input allows you to limit input only to certain GUI elements. After
-		 * 			enabling selective input use addSelectiveInput* methods to add specific elements that
-		 * 			will be allowed to receive input.
-		 *
-		 * @param	onOutsideClickCallback	Callback that gets triggered when the user
-		 * 									presses a mouse button outside of the selective input area.
-		 */
-		void enableSelectiveInput(std::function<void()> onOutsideClickCallback);
-
-		/**
-		 * @brief	Disables selective input and clears any selective input elements.
-		 */
-		void disableSelectiveInput();
-
-		void addSelectiveInputWidget(const GUIWidget* widget);
-		void addSelectiveInputElement(const GUIElement* element);
-
 		/**
 		 * @brief	Allows you to bridge GUI input from a GUI element into another render target.
 		 *
@@ -150,6 +150,8 @@ namespace BansheeEngine
 		CM::Vector<ElementInfo>::type mElementsInFocus;
 		CM::Vector<ElementInfo>::type mNewElementsInFocus;
 
+		CM::Vector<ElementFocusInfo>::type mForcedFocusElements;
+
 		GUIInputCaret* mInputCaret;
 		GUIInputSelection* mInputSelection;
 
@@ -172,11 +174,6 @@ namespace BansheeEngine
 		HSpriteTexture mTextSelectionTexture;
 		CM::Color mTextSelectionColor;
 
-		// Selective input
-		bool mSelectiveInputActive;
-		CM::Map<const GUIWidget*, SelectiveInputData>::type mSelectiveInputData;
-		std::function<void()> mOnOutsideClickCallback;
-
 		CM::Map<const CM::RenderTexture*, const GUIElement*>::type mInputBridge;
 
 		boost::signals::connection mOnCursorMovedConn;

+ 1 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -62,6 +62,7 @@ namespace BansheeEngine
 	class GUIMenuItem;
 	class GUIContent;
 	class GUIContextMenu;
+	class GUIDropDownHitBox;
 
 	// 2D
 	class TextSprite;

+ 0 - 5
BansheeEngine/Source/BsGUIContextMenu.cpp

@@ -24,9 +24,6 @@ namespace BansheeEngine
 		GameObjectHandle<GUIDropDownBox> dropDownBox = GUIDropDownBoxManager::instance().openDropDownBox(widget.getTarget(), 
 			placement, getDropDownData(), widget.getSkin(), GUIDropDownType::ContextMenu, boost::bind(&GUIContextMenu::onMenuClosed, this));
 
-		GUIManager::instance().enableSelectiveInput(boost::bind(&GUIContextMenu::close, this));
-		GUIManager::instance().addSelectiveInputWidget(dropDownBox.get());
-
 		mContextMenuOpen = true;
 	}
 
@@ -35,14 +32,12 @@ namespace BansheeEngine
 		if(mContextMenuOpen)
 		{
 			GUIDropDownBoxManager::instance().closeDropDownBox();
-			GUIManager::instance().disableSelectiveInput();
 			mContextMenuOpen = false;
 		}
 	}
 
 	void GUIContextMenu::onMenuClosed()
 	{
-		GUIManager::instance().disableSelectiveInput();
 		mContextMenuOpen = false;
 	}
 }

+ 47 - 1
BansheeEngine/Source/BsGUIDropDownBox.cpp

@@ -9,6 +9,7 @@
 #include "BsGUIListBox.h"
 #include "BsGUIDropDownBoxManager.h"
 #include "CmSceneObject.h"
+#include "BsGUIDropDownHitBox.h"
 
 using namespace CamelotFramework;
 
@@ -76,7 +77,7 @@ namespace BansheeEngine
 		const GUIDropDownData& dropDownData, const GUISkin& skin, GUIDropDownType type)
 		:GUIWidget(parent, target), mScrollUpStyle(nullptr),
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
-		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr)
+		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mHitBox(nullptr)
 	{
 		String stylePrefix = "";
 		switch(type)
@@ -107,15 +108,54 @@ namespace BansheeEngine
 
 		mLocalizedEntryNames = dropDownData.localizedNames;
 
+		mHitBox = GUIDropDownHitBox::create(*this);
+		mHitBox->onFocusLost.connect(boost::bind(&GUIDropDownBox::dropDownFocusLost, this));
+		mHitBox->setFocus(true);
+
 		RectI availableBounds(target->getX(), target->getY(), target->getWidth(), target->getHeight());
 		mRootMenu = cm_new<DropDownSubMenu>(this, placement, availableBounds, dropDownData, type, 0);
 	}
 
 	GUIDropDownBox::~GUIDropDownBox()
 	{
+		GUIElement::destroy(mHitBox);
 		cm_delete(mRootMenu);
 	}
 
+	void GUIDropDownBox::dropDownFocusLost()
+	{
+		mRootMenu->closeSubMenu();
+		GUIDropDownBoxManager::instance().closeDropDownBox();
+	}
+
+	void GUIDropDownBox::notifySubMenuOpened(DropDownSubMenu* subMenu)
+	{
+		Vector<RectI>::type bounds;
+
+		while(subMenu != nullptr)
+		{
+			bounds.push_back(subMenu->getVisibleBounds());
+
+			subMenu = subMenu->mSubMenu;
+		}
+
+		mHitBox->setBounds(bounds);
+	}
+
+	void GUIDropDownBox::notifySubMenuClosed(DropDownSubMenu* subMenu)
+	{
+		Vector<RectI>::type bounds;
+
+		while(subMenu != nullptr)
+		{
+			bounds.push_back(subMenu->getVisibleBounds());
+
+			subMenu = subMenu->mSubMenu;
+		}
+
+		mHitBox->setBounds(bounds);
+	}
+
 	GUIDropDownBox::DropDownSubMenu::DropDownSubMenu(GUIDropDownBox* owner, const GUIDropDownAreaPlacement& placement, 
 		const RectI& availableBounds, const GUIDropDownData& dropDownData, GUIDropDownType type, UINT32 depthOffset)
 		:mOwner(owner), mPage(0), mBackgroundFrame(nullptr), mBackgroundArea(nullptr), mContentArea(nullptr), 
@@ -228,12 +268,16 @@ namespace BansheeEngine
 		mBackgroundArea->getLayout().addElement(mBackgroundFrame);
 
 		updateGUIElements();
+
+		mOwner->notifySubMenuOpened(this);
 	}
 
 	GUIDropDownBox::DropDownSubMenu::~DropDownSubMenu()
 	{
 		closeSubMenu();
 
+		mOwner->notifySubMenuClosed(this);
+
 		for(auto& elem : mCachedSeparators)
 			GUIElement::destroy(elem);
 
@@ -433,6 +477,8 @@ namespace BansheeEngine
 		mBackgroundArea->setSize(width, usedHeight);
 		mBackgroundArea->setPosition(x, actualY);
 
+		mVisibleBounds = RectI(x, actualY, width, usedHeight);
+
 		UINT32 contentWidth = (UINT32)std::max(0, (INT32)width - (INT32)mOwner->mBackgroundStyle->margins.left - (INT32)mOwner->mBackgroundStyle->margins.right);
 		UINT32 contentHeight = (UINT32)std::max(0, (INT32)usedHeight - (INT32)mOwner->mBackgroundStyle->margins.top - (INT32)mOwner->mBackgroundStyle->margins.bottom);
 		mContentArea->setSize(contentWidth, contentHeight);

+ 76 - 0
BansheeEngine/Source/BsGUIDropDownHitBox.cpp

@@ -0,0 +1,76 @@
+#include "BsGUIDropDownHitBox.h"
+#include "BsGUICommandEvent.h"
+#include "BsGUIWidget.h"
+#include "BsGUISkin.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	const CM::String& GUIDropDownHitBox::getGUITypeName()
+	{
+		static String name = "DropDownHitBox";
+		return name;
+	}
+
+	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin& skin = parent.getSkin();
+			style = skin.getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, style, GUILayoutOptions::create(style));
+	}
+
+	GUIDropDownHitBox* GUIDropDownHitBox::create(GUIWidget& parent, const GUIOptions& layoutOptions, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin& skin = parent.getSkin();
+			style = skin.getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIDropDownHitBox, PoolAlloc>()) GUIDropDownHitBox(parent, style, GUILayoutOptions::create(layoutOptions, style));
+	}
+
+	GUIDropDownHitBox::GUIDropDownHitBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(parent, layoutOptions)
+	{
+
+	}
+
+	bool GUIDropDownHitBox::commandEvent(const GUICommandEvent& ev)
+	{
+		bool processed = GUIElementContainer::commandEvent(ev);
+
+		if(ev.getType() == GUICommandEventType::FocusGained)
+		{
+			if(!onFocusGained.empty())
+				onFocusGained();
+
+			return true;
+		}
+		else if(ev.getType() == GUICommandEventType::FocusLost)
+		{
+			if(!onFocusLost.empty())
+				onFocusLost();
+
+			return true;
+		}
+
+		return processed;
+	}
+
+	bool GUIDropDownHitBox::_isInBounds(const CM::Vector2I position) const
+	{
+		for(auto& bound : mBounds)
+		{
+			if(bound.contains(position))
+				return true;
+		}
+
+		return false;
+	}
+};

+ 5 - 0
BansheeEngine/Source/BsGUIElement.cpp

@@ -137,6 +137,11 @@ namespace BansheeEngine
 		return RectI(mOffset.x, mOffset.y, mWidth, mHeight);
 	}
 
+	void GUIElement::setFocus(bool enabled)
+	{
+		GUIManager::instance().setFocus(this, enabled);
+	}
+
 	RectI GUIElement::getVisibleBounds() const
 	{
 		RectI bounds = _getClippedBounds();

+ 4 - 0
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -536,6 +536,10 @@ namespace BansheeEngine
 		if(ev.getType() == GUICommandEventType::FocusGained)
 		{
 			mActiveTexture = mStyle->focused.texture;
+
+			clearSelection();
+			showCaret();
+
 			markContentAsDirty();
 
 			mHasFocus = true;

+ 0 - 7
BansheeEngine/Source/BsGUIListBox.cpp

@@ -120,10 +120,6 @@ namespace BansheeEngine
 		GameObjectHandle<GUIDropDownBox> dropDownBox = GUIDropDownBoxManager::instance().openDropDownBox(widget.getTarget(), 
 			placement, dropDownData, widget.getSkin(), GUIDropDownType::MenuBar, boost::bind(&GUIListBox::onListBoxClosed, this));
 
-		GUIManager::instance().enableSelectiveInput(boost::bind(&GUIListBox::closeListBox, this));
-		GUIManager::instance().addSelectiveInputWidget(dropDownBox.get());
-		GUIManager::instance().addSelectiveInputElement(this);
-
 		_setOn(true);
 		mIsListBoxOpen = true;
 	}
@@ -133,7 +129,6 @@ namespace BansheeEngine
 		if(mIsListBoxOpen)
 		{
 			GUIDropDownBoxManager::instance().closeDropDownBox();
-			GUIManager::instance().disableSelectiveInput();
 
 			_setOn(false);
 			mIsListBoxOpen = false;
@@ -142,8 +137,6 @@ namespace BansheeEngine
 
 	void GUIListBox::onListBoxClosed()
 	{
-		GUIManager::instance().disableSelectiveInput();
-
 		_setOn(false);
 		mIsListBoxOpen = false;
 	}

+ 52 - 84
BansheeEngine/Source/BsGUIManager.cpp

@@ -64,7 +64,7 @@ namespace BansheeEngine
 	GUIManager::GUIManager()
 		:mSeparateMeshesByWidget(true), mActiveMouseButton(GUIMouseButton::Left),
 		mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(1.0f, 0.6588f, 0.0f), mIsCaretOn(false),
-		mTextSelectionColor(1.0f, 0.6588f, 0.0f), mInputCaret(nullptr), mInputSelection(nullptr), mSelectiveInputActive(false), mDragState(DragState::NoDrag)
+		mTextSelectionColor(1.0f, 0.6588f, 0.0f), mInputCaret(nullptr), mInputSelection(nullptr), mDragState(DragState::NoDrag)
 	{
 		mOnCursorMovedConn = gInput().onCursorMoved.connect(boost::bind(&GUIManager::onCursorMoved, this, _1));
 		mOnCursorPressedConn = gInput().onCursorPressed.connect(boost::bind(&GUIManager::onCursorPressed, this, _1));
@@ -151,27 +151,6 @@ namespace BansheeEngine
 				mWidgets.erase(findIter);
 		}
 
-		{
-			auto findIter = std::find_if(begin(mElementsUnderCursor), end(mElementsUnderCursor), [=] (const ElementInfo& x) { return x.widget == widget; } );
-
-			if(findIter != mElementsUnderCursor.end())
-				mElementsUnderCursor.erase(findIter);
-		}
-
-		{
-			auto findIter = std::find_if(begin(mElementsInFocus), end(mElementsInFocus), [=] (const ElementInfo& x) { return x.widget == widget; } );
-
-			if(findIter != mElementsInFocus.end())
-				mElementsInFocus.erase(findIter);
-		}
-
-		{
-			auto findIter = std::find_if(begin(mActiveElements), end(mActiveElements), [=] (const ElementInfo& x) { return x.widget == widget; } );
-
-			if(findIter != mActiveElements.end())
-				mActiveElements.erase(findIter);
-		}
-
 		const Viewport* renderTarget = widget->getTarget();
 		GUIRenderData& renderData = mCachedGUIData[renderTarget];
 
@@ -248,6 +227,48 @@ namespace BansheeEngine
 
 		mElementsInFocus.swap(mNewElementsInFocus);
 
+		for(auto& focusElementInfo : mForcedFocusElements)
+		{
+			if(focusElementInfo.element->_isDestroyed())
+				continue;
+
+			if(focusElementInfo.focus)
+			{
+				auto iterFind = std::find_if(mElementsInFocus.begin(), mElementsInFocus.end(), 
+					[&](const ElementInfo& x) { return x.element == focusElementInfo.element; });
+
+				if(iterFind == mElementsInFocus.end())
+				{
+					mElementsInFocus.push_back(ElementInfo(focusElementInfo.element, &focusElementInfo.element->_getParentWidget()));
+
+					mCommandEvent = GUICommandEvent();
+					mCommandEvent.setType(GUICommandEventType::FocusGained);
+
+					sendCommandEvent(&focusElementInfo.element->_getParentWidget(), focusElementInfo.element, mCommandEvent);
+				}
+			}
+			else
+			{
+				mNewElementsInFocus.clear();
+				for(auto& elementInfo : mElementsInFocus)
+				{
+					if(elementInfo.element == focusElementInfo.element)
+					{
+						mCommandEvent = GUICommandEvent();
+						mCommandEvent.setType(GUICommandEventType::FocusLost);
+
+						sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
+					}
+					else
+						mNewElementsInFocus.push_back(elementInfo);
+				}
+
+				mElementsInFocus.swap(mNewElementsInFocus);
+			}
+		}
+
+		mForcedFocusElements.clear();
+
 		processDestroyQueue();
 	}
 
@@ -790,13 +811,6 @@ namespace BansheeEngine
 
 		GUIMouseButton guiButton = buttonToGUIButton(event.button);
 
-		// Send out selective input callback when user clicks on non-selectable element
-		if(mSelectiveInputActive && mElementsUnderCursor.size() == 0)
-		{
-			if(mOnOutsideClickCallback != nullptr)
-				mOnOutsideClickCallback();
-		}
-
 		// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
 		if(mActiveElements.size() == 0)
 		{
@@ -1057,20 +1071,6 @@ namespace BansheeEngine
 				GUIWidget* widget = widgetInfo.widget;
 				if(widgetWindows[widgetIdx] == windowUnderCursor && widget->inBounds(windowToBridgedCoords(*widget, windowPos)))
 				{
-					SelectiveInputData* selectiveInputData = nullptr;
-					if(mSelectiveInputActive)
-					{
-						auto selectionIterFind = mSelectiveInputData.find(widget);
-
-						if(selectionIterFind == mSelectiveInputData.end())
-						{
-							widgetIdx++;
-							continue;
-						}
-						else
-							selectiveInputData = &selectionIterFind->second;
-					}
-
 					const Vector<GUIElement*>::type& elements = widget->getElements();
 					Vector2I localPos = getWidgetRelativePos(*widget, cursorScreenPos);
 
@@ -1081,12 +1081,6 @@ namespace BansheeEngine
 
 						if(!element->_isDisabled() && element->_isInBounds(localPos))
 						{
-							if(mSelectiveInputActive && !selectiveInputData->acceptAllElements)
-							{
-								if(selectiveInputData->elements.find(element) == selectiveInputData->elements.end())
-									continue;
-							}
-
 							mNewElementsUnderCursor.push_back(ElementInfo(element, widget));
 						}
 					}
@@ -1254,6 +1248,15 @@ namespace BansheeEngine
 		mScheduledForDestruction.push(element);
 	}
 
+	void GUIManager::setFocus(GUIElement* element, bool focus)
+	{
+		ElementFocusInfo efi;
+		efi.element = element;
+		efi.focus = focus;
+
+		mForcedFocusElements.push_back(efi);
+	}
+
 	void GUIManager::processDestroyQueue()
 	{
 		// Need two loops and a temporary since element destructors may themselves
@@ -1271,41 +1274,6 @@ namespace BansheeEngine
 		}
 	}
 
-	// HACK - This callback is very hackish and very specific. Attempt to replace it with a more
-	// general purpose solution
-	void GUIManager::enableSelectiveInput(std::function<void()> onOutsideClickCallback)
-	{
-		mSelectiveInputActive = true;
-		mOnOutsideClickCallback = onOutsideClickCallback;
-	}
-
-	void GUIManager::disableSelectiveInput()
-	{
-		mSelectiveInputData.clear();
-		mSelectiveInputActive = false;
-		mOnOutsideClickCallback = nullptr;
-	}
-
-	void GUIManager::addSelectiveInputWidget(const GUIWidget* widget)
-	{
-		auto findIter = mSelectiveInputData.find(widget);
-
-		if(findIter == mSelectiveInputData.end())
-		{
-			SelectiveInputData& data = mSelectiveInputData[widget];
-			data.acceptAllElements = true;
-		}
-		else
-		{
-			mSelectiveInputData[widget].acceptAllElements = true;
-		}
-	}
-
-	void GUIManager::addSelectiveInputElement(const GUIElement* element)
-	{
-		mSelectiveInputData[&element->_getParentWidget()].elements.insert(element);
-	}
-
 	void GUIManager::setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element)
 	{
 		if(element == nullptr)

+ 1 - 12
CamelotClient/Source/BsGUIMenuBar.cpp

@@ -256,14 +256,6 @@ namespace BansheeEditor
 		GameObjectHandle<GUIDropDownBox> dropDownBox = GUIDropDownBoxManager::instance().openDropDownBox(widget.getTarget(), 
 			placement, dropDownData, widget.getSkin(), GUIDropDownType::MenuBar, boost::bind(&GUIMenuBar::onSubMenuClosed, this));
 
-		GUIManager::instance().enableSelectiveInput(boost::bind(&GUIMenuBar::closeSubMenu, this));
-		GUIManager::instance().addSelectiveInputWidget(dropDownBox.get());
-
-		for(auto& childMenu : mChildMenus)
-		{
-			GUIManager::instance().addSelectiveInputElement(childMenu.button);
-		}
-
 		subMenu->button->_setOn(true);
 
 		mSubMenuButton = subMenu->button;
@@ -275,8 +267,7 @@ namespace BansheeEditor
 		if(mSubMenuOpen)
 		{
 			GUIDropDownBoxManager::instance().closeDropDownBox();
-			GUIManager::instance().disableSelectiveInput();
-			
+
 			mSubMenuButton->_setOn(false);
 			mSubMenuOpen = false;
 		}		
@@ -298,8 +289,6 @@ namespace BansheeEditor
 
 	void GUIMenuBar::onSubMenuClosed()
 	{
-		GUIManager::instance().disableSelectiveInput();
-
 		mSubMenuButton->_setOn(false);
 		mSubMenuOpen = false;
 	}

+ 3 - 1
CamelotClient/Source/BsGUISceneTreeView.cpp

@@ -356,7 +356,8 @@ namespace BansheeEditor
 
 	void GUISceneTreeView::onEditCanceled()
 	{
-		disableEdit(false);
+		if(mEditElement != nullptr)
+			disableEdit(false);
 	}
 
 	void GUISceneTreeView::enableEdit(TreeElement* element)
@@ -365,6 +366,7 @@ namespace BansheeEditor
 
 		mEditElement = element;
 		mNameEditBox->enableRecursively();
+		mNameEditBox->setFocus(true);
 
 		if(element->mElement != nullptr)
 			element->mElement->disableRecursively();

+ 5 - 10
TreeView.txt

@@ -1,15 +1,10 @@
 TODO:
- - Add better TreeViewEditBox texture
  - Callback on tree item select
- - In disableEdit make sure I actually apply name change
-   - Use Undo/Redo system (TODO: Not implemented yet)
  - Clicking on an already selectecd element starts rename 
     - Will likely need some kind of check to ignore double-clicks?
- - Pressing F2 starts rename
  - Context menu with rename
- - Detect when I click outside of input box and disable edit (TODO: Need a way to easily detect this)
- - Delete
-    - Needs Undo/Redo support
+ - When edit box is initially opened, focus on it
+ - Delete with Undo/Redo support
  - Drag and drop
    - If a mouse drag is detected DragAndDropManager is activated
    - Element is not removed from its original position until drag is complete
@@ -19,9 +14,9 @@ TODO:
  - Auto scroll
     - Sliding over top or bottom of the tree view while dragging an element will search GUIElement parents to find a ScrollArea. If it finds one it will attempt to scroll up or down.
 
-Gained/Lost focus refactor:
- - Add Window mouse hooks for detecting a mouse press outside of a window: http://www.codeproject.com/Articles/187869/Your-Desktop-and-Microsoft-s-SetWindowsHookEx
- - Remove Selective input and port DropDownBox so it uses the focus system
+Fix GUIDropDownHitBox 
+ - Ensure it is focused when initially created
+ - Test it works properly
 
  Other:
  - When dragging in tree view automatically expand mouse over elements