Ver código fonte

Added render window functionality for minimize/maximize/restore
Added render window functionality to maximize/restore by double clicking on caption area
Hooked up min/max/close buttons on main window

Marko Pintera 11 anos atrás
pai
commit
9982b0ebd7

+ 59 - 0
BansheeCore/Include/BsRenderWindow.h

@@ -91,6 +91,11 @@ namespace BansheeEngine
 		 */
 		bool isHidden() const { return mHidden; }
 
+		/**
+		 * @brief	Returns true if the window is maximized.
+		 */
+		bool isMaximized() const { return mIsMaximized; }
+
 	protected:
 		friend class RenderWindowCore;
 		friend class RenderWindow;
@@ -101,6 +106,7 @@ namespace BansheeEngine
 		bool mHasFocus = false;
 		bool mHidden = false;
 		bool mIsModal = false;
+		bool mIsMaximized = false;
 	};
 
 	/**
@@ -151,6 +157,22 @@ namespace BansheeEngine
 		 */
 		virtual void setActive(bool state);
 
+		/**
+		 * @brief	Minimizes the window to the taskbar.
+		 */
+		virtual void minimize() { }
+
+		/**
+		 * @brief	Maximizes the window over the entire current screen.
+		 */
+		virtual void maximize() { }
+
+		/**
+		 * @brief	Restores the window to original position and size if it is
+		 *			minimized or maximized.
+		 */
+		virtual void restore() { }
+
         /**
          * @brief	Change the size of the window.
          */
@@ -187,6 +209,28 @@ namespace BansheeEngine
 		 */
 		virtual void _windowFocusLost();
 
+		/**
+		 * @brief	Called when window has been maximized.
+		 *
+		 * @note	Core thread.
+		 */
+		virtual void _notifyMaximized();
+
+		/**
+		 * @brief	Called when window has been minimized.
+		 *
+		 * @note	Core thread.
+		 */
+		virtual void _notifyMinimized();
+
+		/**
+		 * @brief	Called when window has been restored 
+		 *			from minimized or maximized state.
+		 *
+		 * @note	Core thread.
+		 */
+		virtual void _notifyRestored();
+
 	protected:
 		friend class RenderWindow;
 		friend class RenderWindowManager;
@@ -252,6 +296,21 @@ namespace BansheeEngine
 		 */
 		void show(CoreAccessor& accessor);
 
+		/**
+		 * @copydoc	RenderWindowCore::minimize
+		 */
+		void minimize(CoreAccessor& accessor);
+
+		/**
+		 * @copydoc	RenderWindowCore::maximize
+		 */
+		void maximize(CoreAccessor& accessor);
+
+		/**
+		 * @copydoc	RenderWindowCore::restore
+		 */
+		void restore(CoreAccessor& accessor);
+
 		/**
 		 * @copydoc RenderWindowCore::setFullscreen(UINT32, UINT32, float, UINT32)
 		 */

+ 63 - 0
BansheeCore/Source/BsRenderWindow.cpp

@@ -85,6 +85,36 @@ namespace BansheeEngine
 		RenderWindowManager::instance().notifyFocusLost(this);
 	}
 
+	void RenderWindowCore::_notifyMaximized()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+
+		props.mIsMaximized = true;
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
+	}
+
+	void RenderWindowCore::_notifyMinimized()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+
+		props.mIsMaximized = false;
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
+	}
+
+	void RenderWindowCore::_notifyRestored()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		RenderWindowProperties& props = const_cast<RenderWindowProperties&>(getProperties());
+
+		props.mIsMaximized = false;
+		RenderWindowManager::instance().notifyPropertiesDirty(this);
+	}
+
 	const RenderWindowProperties& RenderWindowCore::getProperties() const
 	{
 		return static_cast<const RenderWindowProperties&>(getPropertiesInternal());
@@ -147,6 +177,39 @@ namespace BansheeEngine
 		accessor.queueCommand(std::bind(showFunc, getCore()));
 	}
 
+	void RenderWindow::minimize(CoreAccessor& accessor)
+	{
+		std::function<void(SPtr<RenderWindowCore>)> minimizeFunc =
+			[](SPtr<RenderWindowCore> renderWindow)
+		{
+			renderWindow->minimize();
+		};
+
+		accessor.queueCommand(std::bind(minimizeFunc, getCore()));
+	}
+
+	void RenderWindow::maximize(CoreAccessor& accessor)
+	{
+		std::function<void(SPtr<RenderWindowCore>)> maximizeFunc =
+			[](SPtr<RenderWindowCore> renderWindow)
+		{
+			renderWindow->maximize();
+		};
+
+		accessor.queueCommand(std::bind(maximizeFunc, getCore()));
+	}
+
+	void RenderWindow::restore(CoreAccessor& accessor)
+	{
+		std::function<void(SPtr<RenderWindowCore>)> restoreFunc =
+			[](SPtr<RenderWindowCore> renderWindow)
+		{
+			renderWindow->restore();
+		};
+
+		accessor.queueCommand(std::bind(restoreFunc, getCore()));
+	}
+
 	void RenderWindow::setFullscreen(CoreAccessor& accessor, UINT32 width, UINT32 height,
 		float refreshRate, UINT32 monitorIdx)
 	{

+ 39 - 1
BansheeCore/Source/Win32/BsPlatformWndProc.cpp

@@ -142,6 +142,14 @@ namespace BansheeEngine
 			break;
 		case WM_SIZE:
 			win->_windowMovedOrResized();
+
+			if (wParam == SIZE_MAXIMIZED)
+				win->_notifyMaximized();
+			else if (wParam == SIZE_MINIMIZED)
+				win->_notifyMinimized();
+			else if (wParam == SIZE_RESTORED)
+				win->_notifyRestored();
+
 			break;
 		case WM_SETCURSOR:
 			if(isCursorHidden())
@@ -180,13 +188,27 @@ namespace BansheeEngine
 			}
 			return true;
 		case WM_GETMINMAXINFO:
+		{
 			// Prevent the window from going smaller than some minimu size
 			((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
 			((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
+
+			// Ensure maximizes window has proper size and doesn't cover the entire screen
+			const POINT ptZero = { 0, 0 };
+			HMONITOR primaryMonitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
+
+			MONITORINFO monitorInfo;
+			monitorInfo.cbSize = sizeof(MONITORINFO);
+			GetMonitorInfo(primaryMonitor, &monitorInfo);
+
+			((MINMAXINFO*)lParam)->ptMaxPosition.x = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
+			((MINMAXINFO*)lParam)->ptMaxPosition.y = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
+			((MINMAXINFO*)lParam)->ptMaxSize.x = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
+			((MINMAXINFO*)lParam)->ptMaxSize.y = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
+		}
 			break;
 		case WM_CLOSE:
 			{
-				// TODO - Only stop main loop if primary window is closed!!
 				gCoreApplication().stopMainLoop();
 
 				return 0;
@@ -223,6 +245,22 @@ namespace BansheeEngine
 
 				return HTCLIENT;
 			}
+		case WM_NCLBUTTONDBLCLK:
+			// Maximize/Restore on double-click
+			if (wParam == HTCAPTION)
+			{
+				WINDOWPLACEMENT windowPlacement;
+				windowPlacement.length = sizeof(WINDOWPLACEMENT);
+				GetWindowPlacement(hWnd, &windowPlacement);
+
+				if (windowPlacement.showCmd == SW_MAXIMIZE)
+					ShowWindow(hWnd, SW_RESTORE);
+				else
+					ShowWindow(hWnd, SW_MAXIMIZE);
+
+				return 0;
+			}
+			break;
 		case WM_MOUSELEAVE:
 			{
 				// Note: Right now I track only mouse leaving client area. So it's possible for the "mouse left window" callback

+ 15 - 0
BansheeD3D11RenderSystem/Include/BsD3D11RenderWindow.h

@@ -57,6 +57,21 @@ namespace BansheeEngine
 		 */
 		void setActive(bool state);
 
+		/**
+		 * @copydoc	RenderWindowCore::minimize
+		 */
+		void minimize();
+
+		/**
+		 * @copydoc	RenderWindowCore::maximize
+		 */
+		void maximize();
+
+		/**
+		 * @copydoc	RenderWindowCore::restore
+		 */
+		void restore();
+
 		/**
 		 * @copydoc RenderWindowCore::setFullscreen(UINT32, UINT32, float, UINT32)
 		 */

+ 24 - 0
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -359,6 +359,30 @@ namespace BansheeEngine
 		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
+	void D3D11RenderWindowCore::minimize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+	}
+
+	void D3D11RenderWindowCore::maximize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+	}
+
+	void D3D11RenderWindowCore::restore()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+	}
+
 	void D3D11RenderWindowCore::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 15 - 0
BansheeD3D9RenderSystem/Include/BsD3D9RenderWindow.h

@@ -53,6 +53,21 @@ namespace BansheeEngine
 		 */
 		void setHidden(bool hidden);
 
+		/**
+		 * @copydoc	RenderWindowCore::minimize
+		 */
+		void minimize();
+
+		/**
+		 * @copydoc	RenderWindowCore::maximize
+		 */
+		void maximize();
+
+		/**
+		 * @copydoc	RenderWindowCore::restore
+		 */
+		void restore();
+
 		/**
 		 * @copydoc RenderWindowCore::move
 		 */

+ 24 - 0
BansheeD3D9RenderSystem/Source/BsD3D9RenderWindow.cpp

@@ -346,6 +346,30 @@ namespace BansheeEngine
 		RenderWindowManager::instance().notifyPropertiesDirty(this);
 	}
 
+	void D3D9RenderWindowCore::minimize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+	}
+
+	void D3D9RenderWindowCore::maximize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+	}
+
+	void D3D9RenderWindowCore::restore()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+	}
+
 	void D3D9RenderWindowCore::move(INT32 top, INT32 left)
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 5 - 1
BansheeEditor/Include/BsEditorWidgetLayout.h

@@ -25,14 +25,18 @@ namespace BansheeEngine
 
 	public:
 		EditorWidgetLayout(const DockManagerLayoutPtr& dockLayout);
-		EditorWidgetLayout(const PrivatelyConstruct& dummy) { }
+		EditorWidgetLayout(const PrivatelyConstruct& dummy);
 
 		Vector<Entry>& getEntries() { return mEntries; }
 		const DockManagerLayoutPtr& getDockLayout() const { return mDockLayout; }
 
+		void setIsMainWindowMaximized(bool maximized) { mMaximized = maximized; }
+		bool getIsMainWindowMaximized() const { return mMaximized; }
+
 	private:
 		Vector<Entry> mEntries;
 		DockManagerLayoutPtr mDockLayout;
+		bool mMaximized;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 4 - 0
BansheeEditor/Include/BsEditorWidgetLayoutRTTI.h

@@ -18,6 +18,9 @@ namespace BansheeEngine
 		DockManagerLayoutPtr getDockLayout(EditorWidgetLayout* obj) { return obj->mDockLayout; }
 		void setDockLayout(EditorWidgetLayout* obj, DockManagerLayoutPtr val) { obj->mDockLayout = val; }
 
+		bool& getIsMainWindowMaximized(EditorWidgetLayout* obj) { return obj->mMaximized; }
+		void setIsMainWindowMaximized(EditorWidgetLayout* obj, bool& val) { obj->mMaximized = val; }
+
 	public:
 		EditorWidgetLayoutRTTI()
 		{
@@ -25,6 +28,7 @@ namespace BansheeEngine
 				&EditorWidgetLayoutRTTI::setEntry, &EditorWidgetLayoutRTTI::setEntriesArraySize);
 
 			addReflectablePtrField("mDockLayout", 1, &EditorWidgetLayoutRTTI::getDockLayout, &EditorWidgetLayoutRTTI::setDockLayout);
+			addPlainField("mMaximized", 2, &EditorWidgetLayoutRTTI::getIsMainWindowMaximized, &EditorWidgetLayoutRTTI::setIsMainWindowMaximized);
 		}
 
 		virtual const String& getRTTIName()

+ 1 - 1
BansheeEditor/Include/BsEditorWindowBase.h

@@ -35,7 +35,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns the render window that this editor window is being rendered to.
 		 */
-		RenderWindowPtr _getRenderWindow() const { return mRenderWindow; }
+		RenderWindowPtr getRenderWindow() const { return mRenderWindow; }
 
 	protected:
 		EditorWindowBase();

+ 1 - 1
BansheeEditor/Include/BsGUIMenuBar.h

@@ -29,7 +29,7 @@ namespace BansheeEngine
 		RenderWindow* mParentWindow;
 		GUIWidget* mParentWidget;
 		GUIArea* mMainArea;
-		GUIArea* mBackgroundArea;
+		GUIArea* mBgTextureArea;
 		GUITexture* mBgTexture;
 		GUITexture* mLogoTexture;
 

+ 4 - 4
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -96,11 +96,11 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::WindowCloseButtonNormal = L"WindowCloseBtnNormal.psd";
 	const WString BuiltinEditorResources::WindowCloseButtonHover = L"WindowCloseBtnHover.psd";
 
-	const WString BuiltinEditorResources::WindowMinButtonNormal = L"WindowMaxBtnNormal.psd";
-	const WString BuiltinEditorResources::WindowMinButtonHover = L"WindowMaxBtnHover.psd";
+	const WString BuiltinEditorResources::WindowMinButtonNormal = L"WindowMinBtnNormal.psd"; 
+	const WString BuiltinEditorResources::WindowMinButtonHover = L"WindowMinBtnHover.psd"; 
 
-	const WString BuiltinEditorResources::WindowMaxButtonNormal = L"WindowMinBtnNormal.psd";
-	const WString BuiltinEditorResources::WindowMaxButtonHover = L"WindowMinBtnHover.psd";
+	const WString BuiltinEditorResources::WindowMaxButtonNormal = L"WindowMaxBtnNormal.psd";
+	const WString BuiltinEditorResources::WindowMaxButtonHover = L"WindowMaxBtnHover.psd";
 
 	const WString BuiltinEditorResources::TabbedBarBtnNormal = L"TabbedButtonNormal.psd";
 	const WString BuiltinEditorResources::TabbedBarBtnActive = L"TabbedButtonActive.psd";

+ 2 - 2
BansheeEditor/Source/BsEditorWidget.cpp

@@ -82,7 +82,7 @@ namespace BansheeEngine
 	Vector2I EditorWidgetBase::screenToWidgetPos(const Vector2I& screenPos) const
 	{
 		EditorWindowBase* parentEditorWindow = mParent->getParentWindow();
-		RenderWindowPtr parentRenderWindow = parentEditorWindow->_getRenderWindow();
+		RenderWindowPtr parentRenderWindow = parentEditorWindow->getRenderWindow();
 
 		Vector2I windowPos = parentRenderWindow->screenToWindowPos(screenPos);
 		windowPos.x -= mX;
@@ -94,7 +94,7 @@ namespace BansheeEngine
 	Vector2I EditorWidgetBase::widgetToScreenPos(const Vector2I& widgetPos) const
 	{
 		EditorWindowBase* parentEditorWindow = mParent->getParentWindow();
-		RenderWindowPtr parentRenderWindow = parentEditorWindow->_getRenderWindow();
+		RenderWindowPtr parentRenderWindow = parentEditorWindow->getRenderWindow();
 
 		Vector2I windowPos = widgetPos;
 		windowPos.x += mX;

+ 5 - 1
BansheeEditor/Source/BsEditorWidgetLayout.cpp

@@ -11,7 +11,11 @@ namespace BansheeEngine
 	{ }
 
 	EditorWidgetLayout::EditorWidgetLayout(const DockManagerLayoutPtr& dockLayout)
-		:mDockLayout(dockLayout)
+		:mDockLayout(dockLayout), mMaximized(false)
+	{ }
+
+	EditorWidgetLayout::EditorWidgetLayout(const PrivatelyConstruct& dummy)
+		: mMaximized(false)
 	{ }
 
 	/************************************************************************/

+ 8 - 2
BansheeEditor/Source/BsEditorWidgetManager.cpp

@@ -11,6 +11,7 @@
 #include "BsRenderWindow.h"
 #include "BsRenderWindowManager.h"
 #include "BsVector2I.h"
+#include "BsCoreThread.h"
 
 using namespace std::placeholders;
 
@@ -180,6 +181,8 @@ namespace BansheeEngine
 			}
 		}
 
+		layout->setIsMainWindowMaximized(mainWindow->getRenderWindow()->getProperties().isMaximized());
+
 		return layout;
 	}
 
@@ -226,6 +229,9 @@ namespace BansheeEngine
 			if(widget->_getParent() == nullptr)
 				widget->close();
 		}
+
+		if (layout->getIsMainWindowMaximized())
+			mainWindow->getRenderWindow()->maximize(gCoreAccessor());
 	}
 
 	void EditorWidgetManager::onPointerPressed(const PointerEvent& event)
@@ -235,7 +241,7 @@ namespace BansheeEngine
 			EditorWidgetBase* widget = widgetData.second;
 			EditorWidgetContainer* parentContainer = widget->_getParent();
 			EditorWindowBase* parentWindow = parentContainer->getParentWindow();
-			RenderWindowPtr parentRenderWindow = parentWindow->_getRenderWindow();
+			RenderWindowPtr parentRenderWindow = parentWindow->getRenderWindow();
 			const RenderWindowProperties& props = parentRenderWindow->getProperties();
 
 			if (!props.hasFocus())
@@ -277,7 +283,7 @@ namespace BansheeEngine
 				continue;
 
 			EditorWindowBase* parentWindow = parentContainer->getParentWindow();
-			RenderWindowPtr parentRenderWindow = parentWindow->_getRenderWindow();
+			RenderWindowPtr parentRenderWindow = parentWindow->getRenderWindow();
 
 			if (parentRenderWindow.get() != &window)
 				continue;

+ 13 - 9
BansheeEditor/Source/BsGUIMenuBar.cpp

@@ -11,20 +11,21 @@
 #include "BsGUIDropDownBoxManager.h"
 #include "BsSceneObject.h"
 #include "BsPlatform.h"
+#include "BsCoreThread.h"
 
 namespace BansheeEngine
 {
 	const UINT32 GUIMenuBar::NUM_ELEMENTS_AFTER_CONTENT = 8;
 
 	GUIMenuBar::GUIMenuBar(GUIWidget* parent, RenderWindow* parentWindow)
-		:mParentWidget(parent), mParentWindow(parentWindow), mMainArea(nullptr), mBackgroundArea(nullptr), 
+		:mParentWidget(parent), mParentWindow(parentWindow), mMainArea(nullptr), mBgTextureArea(nullptr), 
 		mBgTexture(nullptr), mLogoTexture(nullptr), mSubMenuOpen(false), mSubMenuButton(nullptr)
 	{
-		mBackgroundArea = GUIArea::create(*parent, 0, 0, 1, 13, 9900);
+		mBgTextureArea = GUIArea::create(*parent, 0, 0, 1, 13, 9900);
 		mMainArea = GUIArea::create(*parent, 0, 0, 1, 13, 9899);
 
 		mBgTexture = GUITexture::create(GUIImageScaleMode::StretchToFit, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()), "MenuBarBg");
-		mBackgroundArea->getLayout().addElement(mBgTexture);
+		mBgTextureArea->getLayout().addElement(mBgTexture);
 
 		mLogoTexture = GUITexture::create(GUIImageScaleMode::StretchToFit, "MenuBarBansheeLogo");
 		GUILayout& mainLayout = mMainArea->getLayout();
@@ -70,16 +71,16 @@ namespace BansheeEngine
 		GUIElement::destroy(mLogoTexture);
 
 		GUIArea::destroy(mMainArea);
-		GUIArea::destroy(mBackgroundArea);
+		GUIArea::destroy(mBgTextureArea);
 	}
 
 	void GUIMenuBar::setArea(INT32 x, INT32 y, UINT32 width, UINT32 height)
 	{
 		mMainArea->setPosition(x, y);
-		mBackgroundArea->setPosition(x, y);
+		mBgTextureArea->setPosition(x, y);
 
 		mMainArea->setSize(width, height);
-		mBackgroundArea->setSize(width, height);
+		mBgTextureArea->setSize(width, height);
 
 		refreshNonClientAreas();
 	}
@@ -291,17 +292,20 @@ namespace BansheeEngine
 
 	void GUIMenuBar::onMinimizeClicked()
 	{
-		// TODO
+		mParentWindow->minimize(gCoreAccessor());
 	}
 
 	void GUIMenuBar::onMaximizeClicked()
 	{
-		// TODO
+		if(mParentWindow->getProperties().isMaximized())
+			mParentWindow->restore(gCoreAccessor());
+		else
+			mParentWindow->maximize(gCoreAccessor());
 	}
 
 	void GUIMenuBar::onCloseClicked()
 	{
-		// TODO
+		gCoreApplication().stopMainLoop();
 	}
 
 	void GUIMenuBar::refreshNonClientAreas()

+ 1 - 1
BansheeEditor/Source/BsSceneViewHandler.cpp

@@ -114,7 +114,7 @@ namespace BansheeEngine
 
 	Vector2I SceneViewHandler::wrapCursorToWindow()
 	{
-		RenderWindowPtr parentWindow = mParentWidget->getParentWindow()->_getRenderWindow();
+		RenderWindowPtr parentWindow = mParentWidget->getParentWindow()->getRenderWindow();
 
 		Vector2I windowPos = parentWindow->screenToWindowPos(Cursor::instance().getScreenPosition());
 		const RenderWindowProperties& rwProps = parentWindow->getProperties();

+ 5 - 0
BansheeEngine/Include/BsGUIButtonBase.h

@@ -68,6 +68,11 @@ namespace BansheeEngine
 		 * @brief	Triggered when pointer that was previously hovering leaves the button.
 		 */
 		Event<void()> onOut;
+
+		/**
+		 * @brief	Triggered when button is clicked twice in rapid succession.
+		 */
+		Event<void()> onDoubleClick;
 	protected:
 		GUIButtonBase(const String& styleName, const GUIContent& content, const GUILayoutOptions& layoutOptions);
 		virtual ~GUIButtonBase();

+ 5 - 0
BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -280,6 +280,11 @@ namespace BansheeEngine
 
 			return true;
 		}
+		else if (ev.getType() == GUIMouseEventType::MouseDoubleClick)
+		{
+			if (!onDoubleClick.empty())
+				onDoubleClick();
+		}
 
 		return false;
 	}

+ 15 - 0
BansheeGLRenderSystem/Include/BsWin32Window.h

@@ -52,6 +52,21 @@ namespace BansheeEngine
 		 */
 		void setHidden(bool hidden);
 
+		/**
+		 * @copydoc	RenderWindowCore::minimize
+		 */
+		void minimize();
+
+		/**
+		 * @copydoc	RenderWindowCore::maximize
+		 */
+		void maximize();
+
+		/**
+		 * @copydoc	RenderWindowCore::restore
+		 */
+		void restore();
+
 		/**
 		 * @copydoc RenderWindowCore::move
 		 */

+ 24 - 0
BansheeGLRenderSystem/Source/BsWin32Window.cpp

@@ -486,6 +486,30 @@ namespace BansheeEngine
 		}
 	}
 
+	void Win32WindowCore::minimize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+	}
+
+	void Win32WindowCore::maximize()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+	}
+
+	void Win32WindowCore::restore()
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (mHWnd)
+			SendMessage(mHWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+	}
+
 	void Win32WindowCore::swapBuffers()
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 3 - 1
TODO.txt

@@ -5,6 +5,9 @@
 When serializing Camera I cannot save the reference to RenderTexture. Make it a Resource?
 Possibly set up automatic refresh in debug mode after initialization? As an ad-hoc unit test
 
+<<<<<Menu bar issues>>>>>
+Double-clicking the title bar should cause the window to maximize
+
 <<<<Multi-resource saving>>>>:
  - Modify Font so it doesn't contain a texture, but instead keeps a handle to it
  - Register it in its meta file
@@ -21,7 +24,6 @@ I can get mono errors by checking g_print calls in goutput.c
 
 Running embedded mono with VS attached causes managed null refs to be registered as access violations
 
-Crash on GLTextureBuffer::download on shutdown (OpenGL error invalid enum)
 Create a stack allocatable custom vector implementation and make getResourceDependencies and getCoreDependencies use it.
  - These methods are called often and cause allocations whenever they are.