Browse Source

Added GUIMenu base class
Updated GUIDropDownBox so it can better deal with sub-menus

Marko Pintera 12 years ago
parent
commit
b60d39677c

+ 0 - 1
BansheeEngine.sln

@@ -44,7 +44,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		DropDown.txt = DropDown.txt
 		EditorWindowDock.txt = EditorWindowDock.txt
 		Notes.txt = Notes.txt
-		PlatformPorting.txt = PlatformPorting.txt
 		RenderOperation.txt = RenderOperation.txt
 		TODO.txt = TODO.txt
 		TODO_2D_GUI.txt = TODO_2D_GUI.txt

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -248,6 +248,7 @@
     <ClInclude Include="Include\BsGUILayoutX.h" />
     <ClInclude Include="Include\BsGUILayout.h" />
     <ClInclude Include="Include\BsGUILayoutY.h" />
+    <ClInclude Include="Include\BsGUIMenu.h" />
     <ClInclude Include="Include\BsGUIScrollBar.h" />
     <ClInclude Include="Include\BsGUIScrollBarHandle.h" />
     <ClInclude Include="Include\BsGUIScrollBarHorz.h" />
@@ -335,6 +336,7 @@
     <ClCompile Include="Source\BsUpdateCallback.cpp" />
     <ClCompile Include="Source\BsGUILayoutX.cpp" />
     <ClCompile Include="Source\BsGUIViewport.cpp" />
+    <ClCompile Include="Source\BsGUIMenu.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -207,6 +207,9 @@
     <ClInclude Include="Include\BsGUIListBox.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIMenu.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -359,5 +362,8 @@
     <ClCompile Include="Source\BsGUIListBox.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIMenu.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 2 - 0
BansheeEngine/Include/BsGUIButton.h

@@ -22,6 +22,8 @@ namespace BansheeEngine
 		void setContent(const GUIContent& content);
 
 		boost::signal<void()> onClick;
+		boost::signal<void()> onHover;
+		boost::signal<void()> onOut;
 	protected:
 		~GUIButton();
 

+ 14 - 3
BansheeEngine/Include/BsGUIDropDownBox.h

@@ -10,22 +10,25 @@ namespace BansheeEngine
 		{
 			Separator,
 			Entry,
-			EntryExpandable
+			SubMenu
 		};
 
 	public:
 		static GUIDropDownData separator();
-		static GUIDropDownData button(const CM::WString& label, std::function<void()> callback, bool isExpandable = false);
+		static GUIDropDownData button(const CM::WString& label, std::function<void()> callback);
+		static GUIDropDownData subMenu(const CM::WString& label, const CM::Vector<GUIDropDownData>::type& entries);
 
 		bool isSeparator() const { return mType == Type::Separator; }
-		bool isExpandable() const { return mType == Type::EntryExpandable; }
+		bool isSubMenu() const { return mType == Type::SubMenu; }
 
 		const CM::WString& getLabel() const { return mLabel; }
 		std::function<void()> getCallback() const { return mCallback; }
+		const CM::Vector<GUIDropDownData>::type& getSubMenuEntries() const { return mChildEntries; }
 	private:
 		GUIDropDownData() { }
 
 		std::function<void()> mCallback;
+		CM::Vector<GUIDropDownData>::type mChildEntries;
 		CM::WString mLabel;
 		Type mType; 
 	};
@@ -52,6 +55,7 @@ namespace BansheeEngine
 	private:
 		static const CM::UINT32 DROP_DOWN_BOX_WIDTH;
 
+		GUIDropDownType mType;
 		CM::Vector<GUIDropDownData>::type mElements;
 		CM::UINT32 mPage;
 		CM::INT32 x, y;
@@ -77,11 +81,18 @@ namespace BansheeEngine
 		GUIArea* mContentArea;
 		GUILayout* mContentLayout;
 
+		CM::HSceneObject mSubMenuSO;
+		CM::GameObjectHandle<GUIDropDownBox> mSubMenuDropDownBox;
+
 		void updateGUIElements();
 
 		void scrollDown();
 		void scrollUp();
 
 		CM::UINT32 getElementHeight(CM::UINT32 idx) const;
+
+		void elementClicked(CM::UINT32 idx);
+		void openSubMenu(CM::UINT32 elementIdx);
+		void closeSubMenu();
 	};
 }

+ 3 - 3
BansheeEngine/Include/BsGUIManager.h

@@ -105,8 +105,8 @@ namespace BansheeEngine
 		// Drop down box
 		bool mDropDownBoxOpenScheduled;
 		bool mDropDownBoxActive;
-		CM::Vector<CM::HSceneObject>::type mDropDownSOs;
-		CM::Vector<CM::GameObjectHandle<GUIDropDownBox>>::type mDropDownBoxes;
+		CM::HSceneObject mDropDownSO;
+		CM::GameObjectHandle<GUIDropDownBox> mDropDownBox;
 		std::function<void(CM::UINT32)> mListBoxSelectionMade;
 
 		boost::signals::connection mOnButtonDownConn;
@@ -144,7 +144,7 @@ namespace BansheeEngine
 		bool handleMouseOver(GUIWidget* widget, GUIElement* element, const CM::Int2& screenMousePos, float wheelScrollAmount = 0.0f);
 
 		void closeDropDownListBox(CM::INT32 selectedIdx);
-		void closeAllDropDownBoxes();
+		void closeDropDownBox();
 
 		GUIMouseButton buttonToMouseButton(CM::ButtonCode code) const;
 		CM::Int2 getWidgetRelativePos(const GUIWidget& widget, const CM::Int2& screenPos) const;

+ 59 - 0
BansheeEngine/Include/BsGUIMenu.h

@@ -0,0 +1,59 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIWidget.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUIMenuItem
+	{
+		struct Comparer 
+		{
+			bool operator() (const GUIMenuItem* lhs, GUIMenuItem* rhs) const
+			{
+				return lhs->mName.compare(rhs->mName) < 0;
+			}
+		};
+
+	public:
+		GUIMenuItem(GUIMenuItem* parent, const CM::WString& name, std::function<void()> callback);
+		~GUIMenuItem();
+
+		void addChild(GUIMenuItem* child) { mChildren.insert(child); }
+
+		CM::UINT32 getNumChildren() const { return (CM::UINT32)mChildren.size(); }
+		const GUIMenuItem* getParent() const { return mParent; }
+		const CM::WString& getName() const { return mName; }
+		const GUIMenuItem* findChild(const CM::WString& name) const;
+
+		CM::Set<GUIMenuItem*, Comparer>::type::const_iterator childBegin() const { return mChildren.cbegin(); }
+		CM::Set<GUIMenuItem*, Comparer>::type::const_iterator childEnd() const { return mChildren.cend(); }
+		void removeChild(const CM::WString& name);
+
+	private:
+		friend class GUIMenu;
+
+		GUIMenuItem* mParent;
+		CM::WString mName;
+		std::function<void()> mCallback;
+		CM::Set<GUIMenuItem*, Comparer>::type mChildren;
+
+		CM::Set<GUIMenuItem*, Comparer>::type::iterator findChildInternal(const CM::WString& name) const;
+		
+	};
+
+	class BS_EXPORT GUIMenu : public GUIWidget
+	{
+	public:
+		GUIMenu(const CM::HSceneObject& parent);
+		~GUIMenu();
+
+		void addMenuItem(const CM::WString& path, std::function<void()> callback);
+		const GUIMenuItem* getMenuItem(const CM::WString& path) const;
+		void removeMenuItem(const GUIMenuItem* item);
+	protected:
+		GUIMenuItem mRootElement;
+
+		void openMenu(const GUIMenuItem* menuItem, const CM::WString& subMenuName);
+	};
+}

+ 6 - 0
BansheeEngine/Source/BsGUIButton.cpp

@@ -286,6 +286,9 @@ namespace BansheeEngine
 			mImageDesc.texture = mStyle->hover.texture;
 			markContentAsDirty();
 
+			if(!onHover.empty())
+				onHover();
+
 			return true;
 		}
 		else if(ev.getType() == GUIMouseEventType::MouseOut)
@@ -293,6 +296,9 @@ namespace BansheeEngine
 			mImageDesc.texture = mStyle->normal.texture;
 			markContentAsDirty();
 
+			if(!onOut.empty())
+				onOut();
+
 			return true;
 		}
 		else if(ev.getType() == GUIMouseEventType::MouseDown)

+ 54 - 8
BansheeEngine/Source/BsGUIDropDownBox.cpp

@@ -7,6 +7,7 @@
 #include "BsGUISkin.h"
 #include "CmViewport.h"
 #include "BsGUIListBox.h"
+#include "CmSceneObject.h"
 
 using namespace CamelotFramework;
 
@@ -23,28 +24,39 @@ namespace BansheeEngine
 		return data;
 	}
 
-	GUIDropDownData GUIDropDownData::button(const CM::WString& label, std::function<void()> callback, bool isExpandable)
+	GUIDropDownData GUIDropDownData::button(const WString& label, std::function<void()> callback)
 	{
 		GUIDropDownData data;
 		data.mLabel = label;
-		data.mType = isExpandable ? Type::EntryExpandable : Type::Entry;
+		data.mType = Type::Entry;
 		data.mCallback = callback;
 
 		return data;
 	}
 
+	GUIDropDownData GUIDropDownData::subMenu(const WString& label, const Vector<GUIDropDownData>::type& entries)
+	{
+		GUIDropDownData data;
+		data.mLabel = label;
+		data.mType = Type::SubMenu;
+		data.mChildEntries = entries;
+
+		return data;
+	}
+
 	GUIDropDownBox::GUIDropDownBox(const HSceneObject& parent)
 		:GUIWidget(parent), mPage(0), mBackgroundFrame(nullptr), mScrollUpStyle(nullptr),
 		mScrollDownStyle(nullptr), mEntryBtnStyle(nullptr), mEntryExpBtnStyle(nullptr), 
 		mSeparatorStyle(nullptr), mBackgroundStyle(nullptr), mBackgroundArea(nullptr), mContentArea(nullptr), 
-		mContentLayout(nullptr), mScrollUpBtn(nullptr), mScrollDownBtn(nullptr), x(0), y(0), width(0), height(0)
+		mContentLayout(nullptr), mScrollUpBtn(nullptr), mScrollDownBtn(nullptr), x(0), y(0), width(0), height(0), 
+		mType(GUIDropDownType::ListBox)
 	{
 
 	}
 
 	GUIDropDownBox::~GUIDropDownBox()
 	{
-
+		closeSubMenu();
 	}
 
 	void GUIDropDownBox::initialize(Viewport* target, RenderWindow* window, GUIElement* parentElem, 
@@ -66,6 +78,7 @@ namespace BansheeEngine
 			break;
 		}
 
+		mType = type;
 		mElements = elements;
 
 		mScrollUpStyle = skin.getStyle(stylePrefix + "ScrollUpBtn");
@@ -79,6 +92,7 @@ namespace BansheeEngine
 		mScrollDownBtnArrow = skin.getStyle("ScrollDownBtnArrow")->normal.texture;
 
 		setDepth(0); // Needs to be in front of everything
+		setSkin(skin);
 
 		Rect dropDownListBounds = parentElem->getBounds();
 
@@ -238,7 +252,7 @@ namespace BansheeEngine
 				mContentLayout->addElement(separator);
 				newSeparators.push_back(separator);
 			}
-			else if(element.isExpandable())
+			else if(element.isSubMenu())
 			{
 				GUIButton* expEntryBtn = nullptr;
 				if(!mCachedExpEntryBtns.empty())
@@ -249,7 +263,7 @@ namespace BansheeEngine
 				else
 				{
 					expEntryBtn = GUIButton::create(*this, mElements[i].getLabel(), mEntryExpBtnStyle);
-					expEntryBtn->onClick.connect(mElements[i].getCallback());
+					expEntryBtn->onHover.connect(boost::bind(&GUIDropDownBox::openSubMenu, this, i));
 				}
 
 				mContentLayout->addElement(expEntryBtn);
@@ -266,7 +280,7 @@ namespace BansheeEngine
 				else
 				{
 					entryBtn = GUIButton::create(*this, mElements[i].getLabel(), mEntryBtnStyle);
-					entryBtn->onClick.connect(mElements[i].getCallback());
+					entryBtn->onClick.connect(boost::bind(&GUIDropDownBox::elementClicked, this,  i));
 				}
 
 				mContentLayout->addElement(entryBtn);
@@ -322,7 +336,7 @@ namespace BansheeEngine
 	{
 		if(mElements[idx].isSeparator())
 			return mSeparatorStyle->height;
-		else if(mElements[idx].isExpandable())
+		else if(mElements[idx].isSubMenu())
 			return mEntryExpBtnStyle->height;
 		else
 			return mEntryBtnStyle->height;
@@ -332,6 +346,8 @@ namespace BansheeEngine
 	{
 		mPage++;
 		updateGUIElements();
+
+		closeSubMenu();
 	}
 
 	void GUIDropDownBox::scrollUp()
@@ -341,5 +357,35 @@ namespace BansheeEngine
 			mPage--;
 			updateGUIElements();
 		}
+
+		closeSubMenu();
+	}
+
+	void GUIDropDownBox::closeSubMenu()
+	{
+		if(mSubMenuSO != nullptr)
+		{
+			mSubMenuSO->destroy();
+			mSubMenuSO = HSceneObject();
+			mSubMenuDropDownBox = GameObjectHandle<GUIDropDownBox>();
+		}
+	}
+
+	void GUIDropDownBox::elementClicked(UINT32 idx)
+	{
+		closeSubMenu();
+
+		mElements[idx].getCallback()();
+	}
+
+	void GUIDropDownBox::openSubMenu(UINT32 idx)
+	{
+		closeSubMenu();
+
+		mSubMenuSO = SceneObject::create("DropDownBox");
+		mSubMenuDropDownBox = mSubMenuSO->addComponent<GUIDropDownBox>();
+
+		// TODO - Need to provide a parent element
+		mSubMenuDropDownBox->initialize(getTarget(), getOwnerWindow(), nullptr, mElements[idx].getSubMenuEntries(), getSkin(), mType);
 	}
 }

+ 9 - 23
BansheeEngine/Source/BsGUIManager.cpp

@@ -508,9 +508,8 @@ namespace BansheeEngine
 		if(mDropDownBoxOpenScheduled || mDropDownBoxActive)
 			closeDropDownListBox(-1);
 
-		CM::HSceneObject so = SceneObject::create("DropDownBox");
-		mDropDownSOs.push_back(so);
-		mDropDownBoxes.push_back(so->addComponent<GUIDropDownBox>());
+		mDropDownSO = SceneObject::create("DropDownBox");
+		mDropDownBox = mDropDownSO->addComponent<GUIDropDownBox>();
 
 		GUIWidget& widget = parentList->_getParentWidget();
 
@@ -522,7 +521,7 @@ namespace BansheeEngine
 			i++;
 		}
 
-		mDropDownBoxes.back()->initialize(widget.getTarget(), widget.getOwnerWindow(), parentList, dropDownData, skin, GUIDropDownType::ListBox);
+		mDropDownBox->initialize(widget.getTarget(), widget.getOwnerWindow(), parentList, dropDownData, skin, GUIDropDownType::ListBox);
 
 		mDropDownBoxOpenScheduled = true;
 		mListBoxSelectionMade = selectedCallback;
@@ -533,18 +532,14 @@ namespace BansheeEngine
 		if(selectedIdx != -1)
 			mListBoxSelectionMade(selectedIdx);
 
-		closeAllDropDownBoxes();
+		closeDropDownBox();
 	}
 
-	void GUIManager::closeAllDropDownBoxes()
+	void GUIManager::closeDropDownBox()
 	{
-		for(auto& dropDownSO : mDropDownSOs)
-			dropDownSO->destroy();
+		mDropDownSO->destroy();
 
 		mDropDownBoxActive = false;
-
-		mDropDownSOs.clear();
-		mDropDownBoxes.clear();
 	}
 
 	void GUIManager::updateCaretTexture()
@@ -654,20 +649,11 @@ namespace BansheeEngine
 			{
 				bool clickedOnDropDownBox = false;
 
-				if(mMouseOverElement != nullptr)
-				{
-					for(auto& dropDownBox : mDropDownBoxes)
-					{
-						if(&mMouseOverElement->_getParentWidget() == dropDownBox.get())
-						{
-							clickedOnDropDownBox = true;
-							break;
-						}
-					}
-				}
+				if(mMouseOverElement != nullptr && (&mMouseOverElement->_getParentWidget() == mDropDownBox.get()))
+					clickedOnDropDownBox = true;
 
 				if(!clickedOnDropDownBox)
-					closeAllDropDownBoxes();
+					closeDropDownBox();
 			}
 		}
 	}

+ 126 - 0
BansheeEngine/Source/BsGUIMenu.cpp

@@ -0,0 +1,126 @@
+#include "BsGUIMenu.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	GUIMenuItem::GUIMenuItem(GUIMenuItem* parent, const CM::WString& name, std::function<void()> callback)
+		:mParent(parent), mName(name), mCallback(callback)
+	{
+
+	}
+
+	GUIMenuItem::~GUIMenuItem()
+	{
+		for(auto& child : mChildren)
+			cm_delete<PoolAlloc>(child);
+	}
+
+	const GUIMenuItem* GUIMenuItem::findChild(const CM::WString& name) const
+	{
+		auto iterFind = findChildInternal(name);
+
+		if(iterFind != mChildren.end())
+			return *iterFind;
+
+		return nullptr;
+	}
+
+	void GUIMenuItem::removeChild(const CM::WString& name)
+	{
+		auto iterFind = findChildInternal(name);
+
+		if(iterFind != mChildren.end())
+		{
+			cm_delete<PoolAlloc>(*iterFind);
+			mChildren.erase(iterFind);
+		}
+	}
+
+	CM::Set<GUIMenuItem*, GUIMenuItem::Comparer>::type::iterator GUIMenuItem::findChildInternal(const CM::WString& name) const
+	{
+		GUIMenuItem tempItem(nullptr, name, nullptr);
+		return mChildren.find(&tempItem);
+	}
+
+	GUIMenu::GUIMenu(const CM::HSceneObject& parent)
+		:GUIWidget(parent), mRootElement(nullptr, L"", nullptr)
+	{
+
+	}
+
+	GUIMenu::~GUIMenu()
+	{
+
+	}
+
+	void GUIMenu::addMenuItem(const CM::WString& path, std::function<void()> callback)
+	{
+		Vector<WString>::type pathElements = StringUtil::split(path, L"/");
+
+		GUIMenuItem* curSubMenu = &mRootElement;
+		for(UINT32 i = 0; i < (UINT32)pathElements.size(); i++)
+		{
+			const WString& pathElem = *(pathElements.begin() + i);
+			auto foundChild = curSubMenu->findChildInternal(pathElem);
+			GUIMenuItem* existingItem = *foundChild;
+
+			if(existingItem == nullptr)
+			{
+				bool isLastElem = i == (UINT32)(pathElements.size() - 1);
+
+				if(isLastElem)
+					existingItem = cm_new<GUIMenuItem, PoolAlloc>(curSubMenu, pathElem, callback);
+				else
+				{
+					const WString& nextPathElem = *(pathElements.begin() + i);
+
+					existingItem = cm_alloc<GUIMenuItem, PoolAlloc>();
+					existingItem = new (existingItem) GUIMenuItem(curSubMenu, pathElem, boost::bind(&GUIMenu::openMenu, this, existingItem, nextPathElem));
+				}
+
+				curSubMenu->addChild(existingItem);
+			}
+
+			curSubMenu = existingItem;
+		}
+	}
+
+	const GUIMenuItem* GUIMenu::getMenuItem(const CM::WString& path) const
+	{
+		Vector<WString>::type pathElements = StringUtil::split(path, L"/");
+
+		const GUIMenuItem* curSubMenu = &mRootElement;
+		for(UINT32 i = 0; i < (UINT32)pathElements.size(); i++)
+		{
+			const WString& pathElem = *(pathElements.begin() + i);
+			auto foundChild = curSubMenu->findChildInternal(pathElem);
+			GUIMenuItem* existingItem = *foundChild;
+
+			if(existingItem == nullptr)
+				return nullptr;
+
+			curSubMenu = existingItem;
+		}
+
+		return curSubMenu;
+	}
+
+	void GUIMenu::removeMenuItem(const GUIMenuItem* item)
+	{
+		GUIMenuItem* parent = item->mParent;
+		assert(parent != nullptr);
+
+		parent->removeChild(item->getName());
+	}
+
+	void GUIMenu::openMenu(const GUIMenuItem* menuItem, const WString& subMenuName)
+	{
+		assert(menuItem != nullptr);
+
+		const GUIMenuItem* subMenu = menuItem->findChild(subMenuName);
+		assert(subMenu != nullptr);
+
+		// TODO
+	}
+}

+ 20 - 21
DropDown.txt

@@ -1,25 +1,24 @@
 GUI ignores image in GUIContent for most elements.
 
-Immediate TODO:
- - Hook up ScrollUp and ScrollDown events in GUIDropDownBox
+Doesn't belong here but as an additional reminder: Remove Component::initialize and instead make multi paramter addComponent
 
- GUIMenuBar
- - Create top level buttons in PS
- - Derives from GUIWidget and can be easily added to a window
- - AddMenuItem("Scene/Components/Camera", addCameraCallback)
-  - Automatically creates entire menu hierarchy (or just adds it to an existing submenu)
- - GetMenuItem("Scene/Components")
-  - Returns a MenuItem which may have multiple MenuItem children
- - RemoveMenuItem(MenuItem* item)
+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
 
-----------------------------
- - Elements can call addContextAction("Name", "Callback")
-   - This will be automatically rendered by GUIManager as a drop down menu when user clicks on it
-     - This kind of drop down menu will require separator buttons
-     - Also buttons with sub-menus
-     - It is probably useful to just add this functionality to DropDownBox
-   - Mousing over a sub-menu should upen another DropDownBox at that location
-     - I might need to modify DropDownBox input parameters so they accept GUElement as a parent, and not just GUIDropDownList
-     - Also another parameter to specify on which side of the GUIElement to open the box
-   - GUIManager drop down system could be extended so it handles multiple drop down boxes from various sources
-    - DropDownLists, context menus and toolbar menus
+GUIContextMenu
+ - GUIElements may specify a context menu, which is retrieved by GUIManager using GUIElement::getContextMenu
+ - Menu is opened at the current mouse position (determined by GUIManager)
+ - GUIContextMenu::open(x, y)
+   - GUIDropDownBox is created with the root elements data
+
+GUIMenuBar
+ - It has a specific position, width and height
+ - It was a GUIArea and its root elements are represented as buttons
+   - CLicking on a button will open up the menu, similar to context menu
+   - GUIManager::openMenu(Vector<GUIDropDownData>, GUIElement* parent)
+
+Test separators
+Test expandable buttons
+ - And hook up on mouse over
+ - ALSO I need to close other menu at the same level upon mouse over on another element
+Test scrollUp/scrollDown

+ 6 - 0
Notes.txt

@@ -25,6 +25,12 @@ Reminders:
 	so this would be helpful in a way I wouldn't need to look up actual element height in EngineGUI.
   - GUI currently ignores tooltips in GUIContent. 
   - A way to initialize BansheeEngine without RenderSystem or any kind of UI. So that it may be used for server building as well.
+  - Calls to "initialize()" should be protected. For example GUIWidget and all its derived classes require the user to separately call initialize() after construction.
+    However a much better option would be to wrap construction and initialization in a create() method and make initialize protected.
+	  - GUIWidget needs to be added using addComponent which makes "create()" method not practical. However I have trouble seeing the need for initialize(),
+	    it could be replaced with a variable parameter version of addComponent.
+  - Profiling: Create an easy to browse list of all loaded Resources (similar to Hierarchy in Unity, just for loaded resources)
+    - Possibly also for all core objects
 
 Potential optimizations:
  - bulkPixelConversion is EXTREMELY poorly unoptimized. Each pixel it calls a separate method that does redudant operations every pixel.

+ 0 - 4
TODO.txt

@@ -9,10 +9,6 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
  - BansheeApplication should probably derive from Camlelot application. Right now user needs to know the difference between 
    gApplication and gBansheeApp, which is non-intuitive (e.g. retrieving a window can be done on gApplication, but running main loop can happen on both
 
-Over the holidays:
- - Profile code to see why it runs to slow in debug (AQTime probably)
- - Window docking/undocking
-
 IMMEDIATE:
  - Clicking on a window to focus and immediately trying to drag/resize it, doesn't work. I first need to click, then click again to drag/resize.
  - OpenGL rendering slows to extremely with time (seems to be related to rendering, possibly GUI, possibly in general Pass/Material/Shader/PassParams)

+ 2 - 0
TODODoc.txt

@@ -16,6 +16,8 @@
    very weird issues.
  - If you're creating a hierarchy of classes with RTTI support, ALL classes in the hierarchy must have RTTI implementations. You cannot just leave
    some out, even if they contain no data. This would create incomplete RTTI class hierarchy which can cause various issues.
+ - If you are manually constructing a class and it has an "initialize()" method, then you need to call it before using the class. Most object creation is wrapped
+   in methods which do this automatically though. ("create()" methods)
  - Notation rules:
     - Method prefixed with _ (i.e. _getDevice()) are internal methods used by the engine systems and normal user should not need to call them unless 
 	  he really knows what is he doing. Those methods might also be marked with "Internal method" notation in their documentation (without the _ prefix).