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

Completely redone how I handle move/resize events. Now windows just specify non-client areas for move and resize and the rest is left to the OS.

Marko Pintera 12 лет назад
Родитель
Сommit
ce39033f5d
51 измененных файлов с 414 добавлено и 536 удалено
  1. 3 4
      BansheeEngine/Include/BsGUIArea.h
  2. 1 1
      BansheeEngine/Include/BsGUIButton.h
  3. 8 3
      BansheeEngine/Include/BsGUIElement.h
  4. 1 1
      BansheeEngine/Include/BsGUIInputBox.h
  5. 1 1
      BansheeEngine/Include/BsGUILabel.h
  6. 1 1
      BansheeEngine/Include/BsGUIScrollArea.h
  7. 1 1
      BansheeEngine/Include/BsGUIScrollBar.h
  8. 1 1
      BansheeEngine/Include/BsGUIScrollBarHandle.h
  9. 1 1
      BansheeEngine/Include/BsGUITexture.h
  10. 1 1
      BansheeEngine/Include/BsGUIToggle.h
  11. 1 1
      BansheeEngine/Include/BsGUIViewport.h
  12. 4 4
      BansheeEngine/Include/BsGUIWidget.h
  13. 1 4
      BansheeEngine/Include/BsGUIWindowFrame.h
  14. 2 2
      BansheeEngine/Source/BsGUIButton.cpp
  15. 9 4
      BansheeEngine/Source/BsGUIElement.cpp
  16. 2 2
      BansheeEngine/Source/BsGUIInputBox.cpp
  17. 2 2
      BansheeEngine/Source/BsGUILabel.cpp
  18. 1 1
      BansheeEngine/Source/BsGUIManager.cpp
  19. 2 2
      BansheeEngine/Source/BsGUIScrollArea.cpp
  20. 2 2
      BansheeEngine/Source/BsGUIScrollBar.cpp
  21. 3 3
      BansheeEngine/Source/BsGUIScrollBarHandle.cpp
  22. 2 2
      BansheeEngine/Source/BsGUITexture.cpp
  23. 2 2
      BansheeEngine/Source/BsGUIToggle.cpp
  24. 1 1
      BansheeEngine/Source/BsGUIViewport.cpp
  25. 2 2
      BansheeEngine/Source/BsGUIWidget.cpp
  26. 3 188
      BansheeEngine/Source/BsGUIWindowFrame.cpp
  27. 1 0
      CamelotClient/Include/BsEditorPrerequisites.h
  28. 2 1
      CamelotClient/Include/BsEditorWindowBase.h
  29. 2 0
      CamelotClient/Include/BsGUITabbedTitleBar.h
  30. 5 0
      CamelotClient/Include/BsGUIWindowFrameWidget.h
  31. 1 1
      CamelotClient/Include/BsGUIWindowMover.h
  32. 1 1
      CamelotClient/Source/BsEditorWindow.cpp
  33. 4 4
      CamelotClient/Source/BsEditorWindowBase.cpp
  34. 28 0
      CamelotClient/Source/BsGUITabbedTitleBar.cpp
  35. 59 0
      CamelotClient/Source/BsGUIWindowFrameWidget.cpp
  36. 3 12
      CamelotClient/Source/BsGUIWindowMover.cpp
  37. 0 20
      CamelotCore/Include/CmCoreThreadAccessor.h
  38. 3 0
      CamelotCore/Include/CmPlatformWndProc.h
  39. 0 12
      CamelotCore/Include/CmRenderWindow.h
  40. 112 0
      CamelotCore/Include/Win32/CmPlatformImpl.h
  41. 94 6
      CamelotCore/Source/CmPlatformWndProc.cpp
  42. 3 0
      CamelotCore/Source/CmRenderWindow.cpp
  43. 28 0
      CamelotCore/Source/Win32/CmPlatformImpl.cpp
  44. 0 6
      CamelotD3D11RenderSystem/Include/CmD3D11RenderWindow.h
  45. 0 64
      CamelotD3D11RenderSystem/Source/CmD3D11RenderWindow.cpp
  46. 0 6
      CamelotD3D9Renderer/Include/CmD3D9RenderWindow.h
  47. 0 65
      CamelotD3D9Renderer/Source/CmD3D9RenderWindow.cpp
  48. 0 6
      CamelotGLRenderer/Include/CmWin32Window.h
  49. 0 65
      CamelotGLRenderer/Source/CmWin32Window.cpp
  50. 10 28
      EditorWindowDock.txt
  51. 0 2
      TODO.txt

+ 3 - 4
BansheeEngine/Include/BsGUIArea.h

@@ -60,12 +60,12 @@ namespace BansheeEngine
 
 		void changeParentWidget(GUIWidget* widget);
 
-		CM::UINT32 x() const { return mLeft; }
-		CM::UINT32 y() const { return mTop; }
+		CM::INT32 x() const { return mLeft; }
+		CM::INT32 y() const { return mTop; }
 		CM::UINT32 width() const { return mWidth; }
 		CM::UINT32 height() const { return mHeight; }
 
-		void _update();
+		void _update();		
 	private:
 		friend class GUIWidget;
 
@@ -83,7 +83,6 @@ namespace BansheeEngine
 		GUIArea(GUIWidget* widget, CM::UINT32 x, CM::UINT32 y, CM::UINT16 depth);
 
 		bool isDirty() const;
-
 		void updateSizeBasedOnParent(CM::UINT32 parentWidth, CM::UINT32 parentHeight);
 
 		static void destroyInternal(GUIArea* area);

+ 1 - 1
BansheeEngine/Include/BsGUIButton.h

@@ -48,7 +48,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 8 - 3
BansheeEngine/Include/BsGUIElement.h

@@ -74,6 +74,11 @@ namespace BansheeEngine
 		 */
 		void updateRenderElements();
 
+		/**
+		 * @brief	Gets non-clipped bounds that were assigned to the element by the parent layout.
+		 */
+		CM::Rect getBounds() const;
+
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool keyEvent(const GUIKeyEvent& ev);
 		virtual bool commandEvent(const GUICommandEvent& ev);
@@ -100,7 +105,7 @@ namespace BansheeEngine
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const { return _getDepth(); }
 		Type _getType() const { return GUIElementBase::Type::Element; }
 
-		const CM::Rect& _getBounds() const { return mBounds; }
+		const CM::Rect& _getClippedBounds() const { return mClippedBounds; }
 		CM::UINT32 _getDepth() const { return mDepth; }
 		GUIWidget& _getParentWidget() const { return *mParent; }
 		virtual bool _isInBounds(const CM::Int2 position) const;
@@ -121,7 +126,7 @@ namespace BansheeEngine
 		const GUILayoutOptions& _getLayoutOptions() const { return mLayoutOptions; }
 	protected:
 		virtual void updateRenderElementsInternal();
-		virtual void updateBounds() = 0;
+		virtual void updateClippedBounds() = 0;
 
 		void setLayoutOptions(const GUILayoutOptions& layoutOptions);
 		
@@ -133,7 +138,7 @@ namespace BansheeEngine
 
 		GUIWidget* mParent;
 		GUILayoutOptions mLayoutOptions;
-		CM::Rect mBounds;
+		CM::Rect mClippedBounds;
 
 		bool mAcceptsKeyboardFocus;
 		CM::UINT32 mDepth;

+ 1 - 1
BansheeEngine/Include/BsGUIInputBox.h

@@ -46,7 +46,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUILabel.h

@@ -48,7 +48,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUIScrollArea.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUIScrollBar.h

@@ -56,7 +56,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUIScrollBarHandle.h

@@ -57,7 +57,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUITexture.h

@@ -57,7 +57,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUIToggle.h

@@ -59,7 +59,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
BansheeEngine/Include/BsGUIViewport.h

@@ -51,7 +51,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		/**
 		 * @copydoc GUIElement::updateRenderElementsInternal()

+ 4 - 4
BansheeEngine/Include/BsGUIWidget.h

@@ -77,15 +77,15 @@ namespace BansheeEngine
 
 		void registerArea(GUIArea* area);
 		void unregisterArea(GUIArea* area);
-	private:
-		GUIWidget(const GUIWidget& other) { }
-
-		void updateBounds() const;
 
 		virtual void ownerWindowResized();
 		virtual void ownerWindowFocusChanged();
 
 		virtual void update();
+	private:
+		GUIWidget(const GUIWidget& other) { }
+
+		void updateBounds() const;
 
 		CM::RenderWindow* mOwnerWindow;
 		CM::Viewport* mTarget;

+ 1 - 4
BansheeEngine/Include/BsGUIWindowFrame.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;
@@ -56,10 +56,7 @@ namespace BansheeEngine
 	private:
 		ImageSprite* mImageSprite;
 		IMAGE_SPRITE_DESC mDesc;
-		bool mResizeCursorSet;
 
 		GUIWindowFrame(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
-
-		virtual bool mouseEvent(const GUIMouseEvent& ev);
 	};
 }

+ 2 - 2
BansheeEngine/Source/BsGUIButton.cpp

@@ -118,9 +118,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIButton::updateBounds()
+	void GUIButton::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUIButton::_getOptimalWidth() const

+ 9 - 4
BansheeEngine/Source/BsGUIElement.cpp

@@ -32,7 +32,7 @@ namespace BansheeEngine
 
 	void GUIElement::updateRenderElementsInternal()
 	{
-		updateBounds();
+		updateClippedBounds();
 	}
 
 	void GUIElement::setLayoutOptions(const GUILayoutOptions& layoutOptions) 
@@ -87,7 +87,7 @@ namespace BansheeEngine
 			markMeshAsDirty();
 
 			mOffset = offset;
-			updateBounds();
+			updateClippedBounds();
 		}
 	}
 
@@ -114,7 +114,7 @@ namespace BansheeEngine
 			markMeshAsDirty();
 
 			mClipRect = clipRect; 
-			updateBounds();
+			updateClippedBounds();
 		}
 	}
 
@@ -134,9 +134,14 @@ namespace BansheeEngine
 		GUIElementBase::_changeParentWidget(widget);
 	}
 
+	Rect GUIElement::getBounds() const
+	{
+		return Rect(mOffset.x, mOffset.y, mWidth, mHeight);
+	}
+
 	Rect GUIElement::getVisibleBounds() const
 	{
-		Rect bounds = _getBounds();
+		Rect bounds = _getClippedBounds();
 		
 		bounds.x += mStyle->margins.left;
 		bounds.y += mStyle->margins.top;

+ 2 - 2
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -137,9 +137,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIInputBox::updateBounds()
+	void GUIInputBox::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	Sprite* GUIInputBox::renderElemToSprite(UINT32 renderElemIdx, UINT32& localRenderElemIdx) const

+ 2 - 2
BansheeEngine/Source/BsGUILabel.cpp

@@ -53,9 +53,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUILabel::updateBounds()
+	void GUILabel::updateClippedBounds()
 	{
-		mBounds = mTextSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mTextSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUILabel::_getOptimalWidth() const

+ 1 - 1
BansheeEngine/Source/BsGUIManager.cpp

@@ -299,7 +299,7 @@ namespace BansheeEngine
 				UINT32 renderElemIdx = elem.renderElement;
 				UINT32 elemDepth = guiElem->_getRenderElementDepth(renderElemIdx);
 
-				Rect tfrmedBounds = guiElem->_getBounds();
+				Rect tfrmedBounds = guiElem->_getClippedBounds();
 				tfrmedBounds.transform(guiElem->_getParentWidget().SO()->getWorldTfrm());
 
 				const HMaterial& mat = guiElem->getMaterial(renderElemIdx);

+ 2 - 2
BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -50,9 +50,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIScrollArea::updateBounds()
+	void GUIScrollArea::updateClippedBounds()
 	{
-		mBounds = Rect(0, 0, 0, 0); // We don't want any mouse input for this element. This is just a container.
+		mClippedBounds = Rect(0, 0, 0, 0); // We don't want any mouse input for this element. This is just a container.
 	}
 
 	UINT32 GUIScrollArea::_getOptimalWidth() const

+ 2 - 2
BansheeEngine/Source/BsGUIScrollBar.cpp

@@ -94,9 +94,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIScrollBar::updateBounds()
+	void GUIScrollBar::updateClippedBounds()
 	{
-		mBounds = Rect(0, 0, 0, 0); // We don't want any mouse input for this element. This is just a container.
+		mClippedBounds = Rect(0, 0, 0, 0); // We don't want any mouse input for this element. This is just a container.
 	}
 
 	UINT32 GUIScrollBar::_getOptimalWidth() const

+ 3 - 3
BansheeEngine/Source/BsGUIScrollBarHandle.cpp

@@ -121,12 +121,12 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIScrollBarHandle::updateBounds()
+	void GUIScrollBarHandle::updateClippedBounds()
 	{
-		mBounds = Rect(mOffset.x, mOffset.y, mWidth, mHeight);
+		mClippedBounds = Rect(mOffset.x, mOffset.y, mWidth, mHeight);
 
 		Rect localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
-		mBounds.clip(localClipRect);
+		mClippedBounds.clip(localClipRect);
 	}
 
 	UINT32 GUIScrollBarHandle::_getOptimalWidth() const

+ 2 - 2
BansheeEngine/Source/BsGUITexture.cpp

@@ -162,9 +162,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUITexture::updateBounds()
+	void GUITexture::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUITexture::_getOptimalWidth() const

+ 2 - 2
BansheeEngine/Source/BsGUIToggle.cpp

@@ -243,9 +243,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIToggle::updateBounds()
+	void GUIToggle::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUIToggle::_getOptimalWidth() const

+ 1 - 1
BansheeEngine/Source/BsGUIViewport.cpp

@@ -75,7 +75,7 @@ namespace BansheeEngine
 		return 0;
 	}
 
-	void GUIViewport::updateBounds()
+	void GUIViewport::updateClippedBounds()
 	{
 		Rect mBounds = Rect(0, 0, mWidth, mHeight);
 		mBounds.clip(mClipRect);

+ 2 - 2
BansheeEngine/Source/BsGUIWidget.cpp

@@ -299,11 +299,11 @@ namespace BansheeEngine
 	void GUIWidget::updateBounds() const
 	{
 		if(mElements.size() > 0)
-			mBounds = mElements[0]->_getBounds();
+			mBounds = mElements[0]->_getClippedBounds();
 
 		for(auto& elem : mElements)
 		{
-			Rect elemBounds = elem->_getBounds();
+			Rect elemBounds = elem->_getClippedBounds();
 			mBounds.encapsulate(elemBounds);
 		}
 	}

+ 3 - 188
BansheeEngine/Source/BsGUIWindowFrame.cpp

@@ -14,83 +14,6 @@ using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	enum class FrameSubArea
-	{
-		TopLeft, TopCenter, TopRight,
-		MiddleLeft, Middle, MiddleRight,
-		BottomLeft, BottomCenter, BottomRight,
-		None
-	};
-
-	FrameSubArea getFrameSubArea(const Int2& position, const Rect& bounds)
-	{
-		INT32 x0 = bounds.x;
-		INT32 x1 = bounds.x + 3;
-		INT32 x2 = bounds.x + bounds.width - 3;
-		INT32 x3 = bounds.x + bounds.width;
-
-		INT32 y0 = bounds.y;
-		INT32 y1 = bounds.y + 3;
-		INT32 y2 = bounds.y + bounds.height - 3;
-		INT32 y3 = bounds.y + bounds.height;
-
-		if(position.x >= x0 && position.x < x1 &&
-			position.y >= y0 && position.y < y1)
-		{
-			return FrameSubArea::TopLeft;
-		}
-
-		if(position.x >= x1 && position.x < x2 &&
-			position.y >= y0 && position.y < y1)
-		{
-			return FrameSubArea::TopCenter;
-		}
-
-		if(position.x >= x2 && position.x < x3 &&
-			position.y >= y0 && position.y < y1)
-		{
-			return FrameSubArea::TopRight;
-		}
-
-		if(position.x >= x0 && position.x < x1 &&
-			position.y >= y1 && position.y < y2)
-		{
-			return FrameSubArea::MiddleLeft;
-		}
-
-		if(position.x >= x1 && position.x < x2 &&
-			position.y >= y1 && position.y < y2)
-		{
-			return FrameSubArea::Middle;
-		}
-
-		if(position.x >= x2 && position.x < x3 &&
-			position.y >= y1 && position.y < y2)
-		{
-			return FrameSubArea::MiddleRight;
-		}
-
-		if(position.x >= x0 && position.x < x1 &&
-			position.y >= y2 && position.y < y3)
-		{
-			return FrameSubArea::BottomLeft;
-		}
-
-		if(position.x >= x1 && position.x < x2 &&
-			position.y >= y2 && position.y < y3)
-		{
-			return FrameSubArea::BottomCenter;
-		}
-
-		if(position.x >= x2 && position.x < x3 &&
-			position.y >= y2 && position.y < y3)
-		{
-			return FrameSubArea::BottomRight;
-		}
-
-		return FrameSubArea::None;
-	}
-
 	const String& GUIWindowFrame::getGUITypeName()
 	{
 		static String name = "WindowFrame";
@@ -98,7 +21,7 @@ namespace BansheeEngine
 	}
 
 	GUIWindowFrame::GUIWindowFrame(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
-		:GUIElement(parent, style, layoutOptions, false), mResizeCursorSet(false)
+		:GUIElement(parent, style, layoutOptions, false)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 
@@ -167,9 +90,9 @@ namespace BansheeEngine
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIWindowFrame::updateBounds()
+	void GUIWindowFrame::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUIWindowFrame::_getOptimalWidth() const
@@ -194,15 +117,6 @@ namespace BansheeEngine
 
 	bool GUIWindowFrame::_isInBounds(const CM::Int2 position) const
 	{
-		Rect contentBounds = getVisibleBounds();
-
-		if(!contentBounds.contains(position))
-			return false;
-
-		FrameSubArea subArea = getFrameSubArea(position, contentBounds);
-		if(subArea != FrameSubArea::None && subArea != FrameSubArea::Middle)
-			return true;
-
 		return false;
 	}
 
@@ -221,103 +135,4 @@ namespace BansheeEngine
 
 		markContentAsDirty();
 	}
-
-	bool GUIWindowFrame::mouseEvent(const GUIMouseEvent& ev)
-	{
-		if(ev.getType() == GUIMouseEventType::MouseMove || ev.getType() == GUIMouseEventType::MouseDrag)
-		{
-			Rect contentBounds = getVisibleBounds();
-
-			FrameSubArea subArea = getFrameSubArea(ev.getPosition(), contentBounds);
-			if(subArea != FrameSubArea::None && subArea != FrameSubArea::Middle)
-			{
-				switch (subArea)
-				{
-				case BansheeEngine::FrameSubArea::TopLeft:
-					Platform::setCursor(CursorType::SizeNWSE);
-					break;
-				case BansheeEngine::FrameSubArea::TopCenter:
-					Platform::setCursor(CursorType::SizeNS);
-					break;
-				case BansheeEngine::FrameSubArea::TopRight:
-					Platform::setCursor(CursorType::SizeNESW);
-					break;
-				case BansheeEngine::FrameSubArea::MiddleLeft:
-					Platform::setCursor(CursorType::SizeWE);
-					break;
-				case BansheeEngine::FrameSubArea::MiddleRight:
-					Platform::setCursor(CursorType::SizeWE);
-					break;
-				case BansheeEngine::FrameSubArea::BottomLeft:
-					Platform::setCursor(CursorType::SizeNESW);
-					break;
-				case BansheeEngine::FrameSubArea::BottomCenter:
-					Platform::setCursor(CursorType::SizeNS);
-					break;
-				case BansheeEngine::FrameSubArea::BottomRight:
-					Platform::setCursor(CursorType::SizeNWSE);
-					break;
-				}
-
-				mResizeCursorSet = true;
-
-				return true;
-			}
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseDown)
-		{
-			Rect contentBounds = getVisibleBounds();
-
-			FrameSubArea subArea = getFrameSubArea(ev.getPosition(), contentBounds);
-			if(subArea != FrameSubArea::None && subArea != FrameSubArea::Middle)
-			{
-				RenderWindow* window = _getParentWidget().getOwnerWindow();
-				RenderWindowPtr windowPtr = std::static_pointer_cast<RenderWindow>(window->getThisPtr());
-
-				switch (subArea)
-				{
-				case BansheeEngine::FrameSubArea::TopLeft:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::TopLeft);
-					break;
-				case BansheeEngine::FrameSubArea::TopCenter:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::Top);
-					break;
-				case BansheeEngine::FrameSubArea::TopRight:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::TopRight);
-					break;
-				case BansheeEngine::FrameSubArea::MiddleLeft:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::Left);
-					break;
-				case BansheeEngine::FrameSubArea::MiddleRight:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::Right);
-					break;
-				case BansheeEngine::FrameSubArea::BottomLeft:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::BottomLeft);
-					break;
-				case BansheeEngine::FrameSubArea::BottomCenter:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::Bottom);
-					break;
-				case BansheeEngine::FrameSubArea::BottomRight:
-					gMainCA().startResize(windowPtr, WindowResizeDirection::BottomRight);
-					break;
-				}
-
-				return true;
-			}
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseOut || ev.getType() == GUIMouseEventType::MouseDragEnd)
-		{
-			if(mResizeCursorSet)
-			{
-				Platform::setCursor(CursorType::Arrow);
-				mResizeCursorSet = false;
-
-				return true;
-			}
-		}
-
-		return false;
-	}
 }

+ 1 - 0
CamelotClient/Include/BsEditorPrerequisites.h

@@ -15,6 +15,7 @@ namespace BansheeEditor
 	class EditorWindowManager;
 	class DockManager;
 	class MainEditorWindow;
+	class WindowFrameWidget;
 
 	enum class DragAndDropType
 	{

+ 2 - 1
CamelotClient/Include/BsEditorWindowBase.h

@@ -25,9 +25,11 @@ namespace BansheeEditor
 		EditorWindowBase();
 		EditorWindowBase(CM::RenderWindowPtr renderWindow);
 
+		CM::RenderWindowPtr mRenderWindow;
 		CM::HSceneObject mSceneObject;
 		BS::HGUIWidget mGUI;
 		BS::HCamera mCamera;
+		CM::GameObjectHandle<WindowFrameWidget> mWindowFrame;
 		bool mOwnsRenderWindow;
 
 		void construct(CM::RenderWindowPtr renderWindow);
@@ -35,7 +37,6 @@ namespace BansheeEditor
 		virtual void movedOrResized() { }
 	private:
 		boost::signals::connection mMoveOrResizeConn;
-		CM::RenderWindowPtr mRenderWindow;
 		
 		void movedOrResized(CM::RenderWindow& renderWindow);
 	};

+ 2 - 0
CamelotClient/Include/BsGUITabbedTitleBar.h

@@ -42,5 +42,7 @@ namespace BansheeEditor
 		void tabDraggedOn(CM::UINT32 tabIdx);
 
 		CM::INT32 uniqueIdxToSeqIdx(CM::UINT32 uniqueIdx) const;
+
+		void refreshNonClientAreas();
 	};
 }

+ 5 - 0
CamelotClient/Include/BsGUIWindowFrameWidget.h

@@ -15,6 +15,8 @@ namespace BansheeEditor
 		virtual void initialize(CM::Viewport* target, CM::RenderWindow* ownerWindow);
 
 	protected:
+		static const CM::UINT32 RESIZE_BORDER_WIDTH;
+
 		BS::GUIArea* mWindowFrameArea;
 		BS::GUIWindowFrame* mWindowFrame;
 
@@ -22,5 +24,8 @@ namespace BansheeEditor
 
 		virtual bool _mouseEvent(BS::GUIElement* element, const BS::GUIMouseEvent& ev);
 		virtual void ownerWindowFocusChanged();
+		virtual void ownerWindowResized();
+
+		void refreshNonClientAreas() const;
 	};
 }

+ 1 - 1
CamelotClient/Include/BsGUIWindowMover.h

@@ -50,7 +50,7 @@ namespace BansheeEditor
 		/**
 		 * @copydoc GUIElement::updateBounds()
 		 */
-		virtual void updateBounds();
+		virtual void updateClippedBounds();
 
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;

+ 1 - 1
CamelotClient/Source/BsEditorWindow.cpp

@@ -11,7 +11,7 @@ namespace BansheeEditor
 		:EditorWindowBase(), mWidgets(cm_new<EditorWidgetContainer>(mGUI.get()))
 	{
 		updateSize();
-
+		
 		mWidgets->onWidgetClosed.connect(boost::bind(&EditorWindow::widgetRemoved, this));
 		mWidgets->onWidgetHidden.connect(boost::bind(&EditorWindow::widgetHidden, this));
 	}

+ 4 - 4
CamelotClient/Source/BsEditorWindowBase.cpp

@@ -79,10 +79,10 @@ namespace BansheeEditor
 
 		mGUI->setSkin(&EngineGUI::instance().getSkin());
 
-		GameObjectHandle<WindowFrameWidget> frame = mSceneObject->addComponent<WindowFrameWidget>();
-		frame->setSkin(&EngineGUI::instance().getSkin());
-		frame->initialize(mCamera->getViewport().get(), renderWindow.get());
-		frame->setDepth(129);
+		mWindowFrame = mSceneObject->addComponent<WindowFrameWidget>();
+		mWindowFrame->setSkin(&EngineGUI::instance().getSkin());
+		mWindowFrame->initialize(mCamera->getViewport().get(), renderWindow.get());
+		mWindowFrame->setDepth(129);
 
 		mMoveOrResizeConn = RenderWindowManager::instance().onMovedOrResized.connect(boost::bind(&EditorWindowBase::movedOrResized, this, _1));
 	}

+ 28 - 0
CamelotClient/Source/BsGUITabbedTitleBar.cpp

@@ -9,6 +9,7 @@
 #include "BsEngineGUI.h"
 #include "BsGUIWidget.h"
 #include "CmMath.h"
+#include "CmPlatform.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
@@ -42,6 +43,8 @@ namespace BansheeEditor
 		mMainLayout->addSpace(3);
 		mMainLayout->addElement(mCloseBtn);
 		mMainArea->getLayout().addSpace(3);
+
+		refreshNonClientAreas();
 	}
 
 	GUITabbedTitleBar::~GUITabbedTitleBar()
@@ -88,6 +91,8 @@ namespace BansheeEditor
 		mMainLayout->insertElement(idx * 2, newDragDropElement);
 
 		mUniqueTabIdx++;
+
+		refreshNonClientAreas();
 	}
 
 	void GUITabbedTitleBar::removeTab(UINT32 idx)
@@ -102,18 +107,24 @@ namespace BansheeEditor
 
 		mTabButtons.erase(mTabButtons.begin() + idx);
 		mDragDropElements.erase(mDragDropElements.begin() + idx);
+
+		refreshNonClientAreas();
 	}
 
 	void GUITabbedTitleBar::setPosition(INT32 x, INT32 y)
 	{
 		mMainArea->setPosition(x, y);
 		mBackgroundArea->setPosition(x, y);
+
+		refreshNonClientAreas();
 	}
 
 	void GUITabbedTitleBar::setSize(UINT32 width, UINT32 height)
 	{
 		mMainArea->setSize(width, height);
 		mBackgroundArea->setSize(width, height);
+
+		refreshNonClientAreas();
 	}
 
 	void GUITabbedTitleBar::tabToggled(CM::UINT32 tabIdx)
@@ -176,4 +187,21 @@ namespace BansheeEditor
 
 		return -1;
 	}
+
+	void GUITabbedTitleBar::refreshNonClientAreas()
+	{
+		// If the size or contents of the area changed this frame the layout won't be updated yet,
+		// so force the update right away so we get correct element bounds
+		mMainArea->_update();
+
+		CM::Vector<CM::Rect>::type nonClientAreas;
+		for(auto& elem : mDragDropElements)
+		{
+			nonClientAreas.push_back(elem->getBounds());
+		}
+
+		nonClientAreas.push_back(mLastDropElement->getBounds());
+
+		Platform::setCaptionNonClientAreas(*mParentWidget->getOwnerWindow(), nonClientAreas);
+	}
 }

+ 59 - 0
CamelotClient/Source/BsGUIWindowFrameWidget.cpp

@@ -7,12 +7,15 @@
 #include "BsGUIMouseEvent.h"
 #include "CmRenderWindow.h"
 #include "CmMath.h"
+#include "CmPlatform.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 
 namespace BansheeEditor
 {
+	const UINT32 WindowFrameWidget::RESIZE_BORDER_WIDTH = 3;
+
 	WindowFrameWidget::WindowFrameWidget(const HSceneObject& parent)
 		:GUIWidget(parent), mWindowFrameArea(nullptr)
 	{
@@ -35,6 +38,8 @@ namespace BansheeEditor
 
 		mWindowFrame = GUIWindowFrame::create(*this, getSkin()->getStyle("WindowFrame"));
 		mWindowFrameArea->getLayout().addElement(mWindowFrame);
+
+		refreshNonClientAreas();
 	}
 
 	void WindowFrameWidget::update()
@@ -50,5 +55,59 @@ namespace BansheeEditor
 	void WindowFrameWidget::ownerWindowFocusChanged()
 	{
 		mWindowFrame->setFocused(getOwnerWindow()->hasFocus());
+
+		GUIWidget::ownerWindowFocusChanged();
+	}
+
+	void WindowFrameWidget::ownerWindowResized()
+	{
+		GUIWidget::ownerWindowResized();
+
+		refreshNonClientAreas();
+	}
+
+	void WindowFrameWidget::refreshNonClientAreas() const
+	{
+		INT32 x = mWindowFrameArea->x();
+		INT32 y = mWindowFrameArea->y();
+
+		UINT32 width = mWindowFrameArea->width();
+		UINT32 height = mWindowFrameArea->height();
+
+		CM::Vector<NonClientResizeArea>::type nonClientAreas(8);
+
+		nonClientAreas[0].type = NonClientAreaBorderType::TopLeft;
+		nonClientAreas[0].area = Rect(x, y, 
+			RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[1].type = NonClientAreaBorderType::Top;
+		nonClientAreas[1].area = Rect(x + RESIZE_BORDER_WIDTH, y, 
+			width - 2 * RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[2].type = NonClientAreaBorderType::TopRight;
+		nonClientAreas[2].area = Rect(x + width - RESIZE_BORDER_WIDTH, y, 
+			RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[3].type = NonClientAreaBorderType::Left;
+		nonClientAreas[3].area = Rect(x, y + RESIZE_BORDER_WIDTH, 
+			RESIZE_BORDER_WIDTH, height - 2 * RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[4].type = NonClientAreaBorderType::Right;
+		nonClientAreas[4].area = Rect(x + width - RESIZE_BORDER_WIDTH, y + RESIZE_BORDER_WIDTH, 
+			RESIZE_BORDER_WIDTH, height - 2 * RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[5].type = NonClientAreaBorderType::BottomLeft;
+		nonClientAreas[5].area = Rect(x, y + height - RESIZE_BORDER_WIDTH, 
+			RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[6].type = NonClientAreaBorderType::Bottom;
+		nonClientAreas[6].area = Rect(x + RESIZE_BORDER_WIDTH, y + height - RESIZE_BORDER_WIDTH, 
+			width - 2 * RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		nonClientAreas[7].type = NonClientAreaBorderType::BottomRight;
+		nonClientAreas[7].area = Rect(x + width - RESIZE_BORDER_WIDTH, y + height - RESIZE_BORDER_WIDTH, 
+			RESIZE_BORDER_WIDTH, RESIZE_BORDER_WIDTH);
+
+		Platform::setResizeNonClientAreas(*getOwnerWindow(), nonClientAreas);
 	}
 }

+ 3 - 12
CamelotClient/Source/BsGUIWindowMover.cpp

@@ -89,9 +89,9 @@ namespace BansheeEditor
 		GUIElement::updateRenderElementsInternal();
 	}
 
-	void GUIWindowMover::updateBounds()
+	void GUIWindowMover::updateClippedBounds()
 	{
-		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 
 	UINT32 GUIWindowMover::_getOptimalWidth() const
@@ -132,16 +132,7 @@ namespace BansheeEditor
 
 	bool GUIWindowMover::mouseEvent(const GUIMouseEvent& ev)
 	{
-		if(ev.getType() == GUIMouseEventType::MouseDown)
-		{
-			RenderWindow* window = _getParentWidget().getOwnerWindow();
-			RenderWindowPtr windowPtr = std::static_pointer_cast<RenderWindow>(window->getThisPtr());
-
-			gMainCA().startMove(windowPtr);
-
-			return true;
-		}
-		else if(ev.getType() == GUIMouseEventType::MouseDragAndDropDropped)
+		if(ev.getType() == GUIMouseEventType::MouseDragAndDropDropped)
 		{
 			if(!onDraggedItemDropped.empty())
 				onDraggedItemDropped();

+ 0 - 20
CamelotCore/Include/CmCoreThreadAccessor.h

@@ -252,26 +252,6 @@ namespace CamelotFramework
 			mCommandQueue->queue(boost::bind(&RenderWindow::move, renderWindow.get(), left, top));
 		}
 
-		void startResize(RenderWindowPtr& renderWindow, WindowResizeDirection direction)
-		{
-			mCommandQueue->queue(boost::bind(&RenderWindow::startResize, renderWindow.get(), direction));
-		}
-
-		void endResize(RenderWindowPtr& renderWindow)
-		{
-			mCommandQueue->queue(boost::bind(&RenderWindow::endResize, renderWindow.get()));
-		}
-
-		void startMove(RenderWindowPtr& renderWindow)
-		{
-			mCommandQueue->queue(boost::bind(&RenderWindow::startMove, renderWindow.get()));
-		}
-
-		void endMove(RenderWindowPtr& renderWindow)
-		{
-			mCommandQueue->queue(boost::bind(&RenderWindow::endMove, renderWindow.get()));
-		}
-
 		void hideWindow(RenderWindowPtr& renderWindow)
 		{
 			mCommandQueue->queue(boost::bind(&RenderWindow::setHidden, renderWindow.get(), true));

+ 3 - 0
CamelotCore/Include/CmPlatformWndProc.h

@@ -9,5 +9,8 @@ namespace CamelotFramework
 	{
 	public:
 		static LRESULT CALLBACK _win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+	private:
+		static LRESULT translateNonClientAreaType(NonClientAreaBorderType type);
 	};
 }

+ 0 - 12
CamelotCore/Include/CmRenderWindow.h

@@ -39,12 +39,6 @@ namespace CamelotFramework
 		Fixed
 	};
 
-	enum class WindowResizeDirection
-	{
-		Left, TopLeft, Top, TopRight,
-		Right, BottomRight, Bottom, BottomLeft
-	};
-
 	struct CM_EXPORT RENDER_WINDOW_DESC
 	{
 		RENDER_WINDOW_DESC()
@@ -142,12 +136,6 @@ namespace CamelotFramework
 		virtual Int2 screenToWindowPos(const Int2& screenPos) const = 0;
 		virtual Int2 windowToScreenPos(const Int2& windowPos) const = 0;
 
-		virtual void startResize(WindowResizeDirection direction) = 0;
-		virtual void endResize() = 0;
-
-		virtual void startMove() = 0;
-		virtual void endMove() = 0;
-
 		virtual void destroy();
 
 		static RenderWindowPtr create(RENDER_WINDOW_DESC& desc, RenderWindowPtr parentWindow = nullptr);

+ 112 - 0
CamelotCore/Include/Win32/CmPlatformImpl.h

@@ -17,6 +17,30 @@ namespace CamelotFramework
 
 		Pimpl* data;
 	};
+	
+	enum class NonClientAreaBorderType
+	{
+		TopLeft,
+		Top,
+		TopRight,
+		Left,
+		Right,
+		BottomLeft,
+		Bottom,
+		BottomRight	
+	};
+
+	struct CM_EXPORT NonClientResizeArea
+	{
+		NonClientAreaBorderType type;
+		Rect area;
+	};
+
+	struct CM_EXPORT WindowNonClientAreaData
+	{
+		Vector<NonClientResizeArea>::type resizeAreas;
+		Vector<Rect>::type moveAreas;
+	};
 
 	/**
 	 * @brief	Provides access for version Windows operating system functions, including
@@ -30,24 +54,109 @@ namespace CamelotFramework
 
 		/**
 		 * @brief	Moves the cursor to the specified screen position.
+		 * 			
+		 * @note	Thread safe. 
 		 */
 		static void setCursorPosition(const Int2& screenPos);
 
+		/**
+		 * @brief	Capture mouse to this window so that we get mouse input even if the mouse leaves the window area.
+		 *
+		 * @note	Thread safe.
+		 */
 		static void captureMouse(const RenderWindow& window);
+		/**
+		 * @brief	Releases the mouse capture set by "captureMouse"
+		 * 			
+		 * @note	Thread safe.
+		 */
 		static void releaseMouseCapture();
 
+		/**
+		 * @brief	Limit cursor movement to the specified window.
+		 *
+		 * @note	Thread safe.
+		 */
 		static void clipCursorToWindow(const RenderWindow& window);
+		/**
+		 * @brief	Clip cursor to specific area on the screen.
+		 *
+		 * @note	Thread safe.
+		 */
 		static void clipCursorToRect(const Rect& screenRect);
+		/**
+		 * @brief	Disables cursor clipping.
+		 * 			
+		 * @note	Thread safe.
+		 */
 		static void clipCursorDisable();
 
+		/**
+		 * @brief	Hides the cursor.
+		 * 			
+		 * @note	Thread safe.
+		 */
 		static void hideCursor();
+		/**
+		 * @brief	Shows the cursor.
+		 * 			
+		 * @note	Thread safe.
+		 */
 		static void showCursor();
 
+		/**
+		 * @brief	Query if the cursor is hidden.
+		 *
+		 * @note	Thread safe.
+		 */
 		static bool isCursorHidden() { return mIsCursorHidden; }
 		
+		/**
+		 * @brief	Sets a cursor icon. Uses built-in platform cursor types.
+		 *
+		 * @note	Thread safe.
+		 */
 		static void setCursor(CursorType type);
+		/**
+		 * @brief	Sets a cursor using a custom image.
+		 *
+		 * @param 	pixelData	Cursor image data.
+		 * @param	hotSpot		Offset on the cursor image to where the actual input happens (e.g. tip of the Arrow cursor).
+		 * 						
+		 * @note	Thread safe.
+		 */
 		static void setCustomCursor(PixelData& pixelData, const Int2& hotSpot);
 
+		/**
+		 * @brief	Sets custom caption non client areas for the specified window. Using custom client
+		 * 			areas will override window move/drag operation and trigger when user interacts
+		 * 			with the custom area.
+		 * 			
+		 * @note	Thread safe.
+		 * 			All provided areas are relative to the specified window.
+		 * 			Mostly useful for frameless windows that don't have typical caption bar.
+		 */
+		static void setCaptionNonClientAreas(const RenderWindow& window, const Vector<Rect>::type& nonClientAreas);
+
+		/**
+		 * @brief	Sets custom non client areas for the specified window. Using custom client
+		 * 			areas will override window resize operation and trigger when user interacts
+		 * 			with the custom area.
+		 * 			
+		 * @note	Thread safe.
+		 * 			All provided areas are relative to the specified window.
+		 * 			Mostly useful for frameless windows that don't have typical border.
+		 */
+		static void setResizeNonClientAreas(const RenderWindow& window, const Vector<NonClientResizeArea>::type& nonClientAreas);
+
+		/**
+		 * @brief	Resets the non client areas for the specified windows and allows 
+		 * 			the platform to use the default values.
+		 * 			
+		 * @note	Thread safe.
+		 */
+		static void resetNonClientAreas(const RenderWindow& window);
+
 		/**
 		 * @brief	Message pump. Processes OS messages and returns when it's free.
 		 * 			
@@ -68,6 +177,9 @@ namespace CamelotFramework
 		static bool mIsCursorHidden;
 		static NativeCursorData mCursor;
 		static bool mUsingCustomCursor;
+		static Map<const RenderWindow*, WindowNonClientAreaData>::type mNonClientAreas;
+
+		CM_STATIC_MUTEX(mSync);
 
 		static void win32ShowCursor();
 		static void win32HideCursor();

+ 94 - 6
CamelotCore/Source/CmPlatformWndProc.cpp

@@ -81,7 +81,37 @@ namespace CamelotFramework
 			if(isCursorHidden())
 				win32HideCursor();
 			else
+			{
+				switch (LOWORD(lParam))
+				{
+				case HTTOPLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZENWSE));
+					return 0;
+				case HTTOP:
+					SetCursor(LoadCursor(0, IDC_SIZENS));
+					return 0;
+				case HTTOPRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZENESW));
+					return 0;
+				case HTLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZEWE));
+					return 0;
+				case HTRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZEWE));
+					return 0;
+				case HTBOTTOMLEFT:
+					SetCursor(LoadCursor(0, IDC_SIZENESW));
+					return 0;
+				case HTBOTTOM:
+					SetCursor(LoadCursor(0, IDC_SIZENS));
+					return 0;
+				case HTBOTTOMRIGHT:
+					SetCursor(LoadCursor(0, IDC_SIZENWSE));
+					return 0;
+				}
+
 				win32ShowCursor();
+			}
 			return true;
 		case WM_GETMINMAXINFO:
 			// Prevent the window from going smaller than some minimu size
@@ -95,13 +125,37 @@ namespace CamelotFramework
 
 				return 0;
 			}
-		case WM_NCLBUTTONUP:
+		case WM_NCHITTEST:
 			{
-				break;
-			}
-		case WM_LBUTTONUP:
-			{
-				break;
+				auto iterFind = mNonClientAreas.find(win);
+				if(iterFind == mNonClientAreas.end())
+					break;
+
+				POINT mousePos;
+				mousePos.x = GET_X_LPARAM(lParam);
+				mousePos.y = GET_Y_LPARAM(lParam); 
+
+				ScreenToClient(hWnd, &mousePos);
+
+				Int2 mousePosInt;
+				mousePosInt.x = mousePos.x;
+				mousePosInt.y = mousePos.y;
+
+				Vector<NonClientResizeArea>::type& resizeAreasPerWindow = iterFind->second.resizeAreas;
+				for(auto area : resizeAreasPerWindow)
+				{
+					if(area.area.contains(mousePosInt))
+						return translateNonClientAreaType(area.type);
+				}
+
+				Vector<Rect>::type& moveAreasPerWindow = iterFind->second.moveAreas;
+				for(auto area : moveAreasPerWindow)
+				{
+					if(area.contains(mousePosInt))
+						return HTCAPTION;
+				}
+
+				return HTCLIENT;
 			}
 		case WM_MOUSEMOVE:
 			{
@@ -192,4 +246,38 @@ namespace CamelotFramework
 
 		return DefWindowProc( hWnd, uMsg, wParam, lParam );
 	}
+
+	LRESULT PlatformWndProc::translateNonClientAreaType(NonClientAreaBorderType type)
+	{
+		LRESULT dir = HTCLIENT;
+		switch(type)
+		{
+		case NonClientAreaBorderType::Left:
+			dir = HTLEFT;
+			break;
+		case NonClientAreaBorderType::TopLeft:
+			dir = HTTOPLEFT;
+			break;
+		case NonClientAreaBorderType::Top:
+			dir = HTTOP;
+			break;
+		case NonClientAreaBorderType::TopRight:
+			dir = HTTOPRIGHT;
+			break;
+		case NonClientAreaBorderType::Right:
+			dir = HTRIGHT;
+			break;
+		case NonClientAreaBorderType::BottomRight:
+			dir = HTBOTTOMRIGHT;
+			break;
+		case NonClientAreaBorderType::Bottom:
+			dir = HTBOTTOM;
+			break;
+		case NonClientAreaBorderType::BottomLeft:
+			dir = HTBOTTOMLEFT;
+			break;
+		}
+
+		return dir;
+	}
 }

+ 3 - 0
CamelotCore/Source/CmRenderWindow.cpp

@@ -29,6 +29,7 @@ THE SOFTWARE.
 #include "CmCoreThread.h"
 #include "CmRenderWindowManager.h"
 #include "CmViewport.h"
+#include "CmPlatform.h"
 
 namespace CamelotFramework 
 {
@@ -77,6 +78,8 @@ namespace CamelotFramework
 
 	void RenderWindow::destroy()
 	{
+		Platform::resetNonClientAreas(*this);
+
 		RenderWindowManager::instance().windowDestroyed(this);
 
 		RenderTarget::destroy();

+ 28 - 0
CamelotCore/Source/Win32/CmPlatformImpl.cpp

@@ -15,6 +15,10 @@ namespace CamelotFramework
 	boost::signal<void(RenderWindow*)> Platform::onWindowMovedOrResized;
 	boost::signal<void()> Platform::onMouseCaptureChanged;
 
+	Map<const RenderWindow*, WindowNonClientAreaData>::type Platform::mNonClientAreas;
+
+	CM_STATIC_MUTEX_CLASS_INSTANCE(mSync, Platform);
+
 	struct NativeCursorData::Pimpl
 	{
 		HCURSOR cursor;
@@ -243,6 +247,30 @@ namespace CamelotFramework
 		PostMessage(hwnd, WM_SETCURSOR, WPARAM(hwnd), (LPARAM)MAKELONG(HTCLIENT, WM_MOUSEMOVE));
 	}
 
+	void Platform::setCaptionNonClientAreas(const RenderWindow& window, const Vector<Rect>::type& nonClientAreas)
+	{
+		CM_LOCK_MUTEX(mSync);
+
+		mNonClientAreas[&window].moveAreas = nonClientAreas;
+	}
+
+	void Platform::setResizeNonClientAreas(const RenderWindow& window, const Vector<NonClientResizeArea>::type& nonClientAreas)
+	{
+		CM_LOCK_MUTEX(mSync);
+
+		mNonClientAreas[&window].resizeAreas = nonClientAreas;
+	}
+
+	void Platform::resetNonClientAreas(const RenderWindow& window)
+	{
+		CM_LOCK_MUTEX(mSync);
+
+		auto iterFind = mNonClientAreas.find(&window);
+
+		if(iterFind != end(mNonClientAreas))
+			mNonClientAreas.erase(iterFind);
+	}
+
 	void Platform::messagePump()
 	{
 		MSG  msg;

+ 0 - 6
CamelotD3D11RenderSystem/Include/CmD3D11RenderWindow.h

@@ -75,12 +75,6 @@ namespace CamelotFramework
 		 */
 		bool requiresTextureFlipping() const { return false; }
 
-		void startResize(WindowResizeDirection direction);
-		void endResize();
-
-		void startMove();
-		void endMove();
-
 		void _windowMovedOrResized();
 
 		DXGI_SWAP_CHAIN_DESC* _getPresentationParameters(void) { return &mSwapChainDesc; }

+ 0 - 64
CamelotD3D11RenderSystem/Source/CmD3D11RenderWindow.cpp

@@ -13,11 +13,6 @@
 
 namespace CamelotFramework
 {
-	void HACK_SendLMBUpEvent()
-	{
-		gInput().simulateButtonUp(BC_MOUSE_LEFT);
-	}
-
 	D3D11RenderWindow::D3D11RenderWindow(const RENDER_WINDOW_DESC& desc,D3D11Device& device, IDXGIFactory* DXGIFactory)
 		: RenderWindow(desc)
 		, mDevice(device)
@@ -551,65 +546,6 @@ namespace CamelotFramework
 		return Int2(pos.x, pos.y);
 	}
 
-
-	void D3D11RenderWindow::startResize(WindowResizeDirection direction)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		WPARAM dir = HTLEFT;
-		switch(direction)
-		{
-		case WindowResizeDirection::Left:
-			dir = HTLEFT;
-			break;
-		case WindowResizeDirection::TopLeft:
-			dir = HTTOPLEFT;
-			break;
-		case WindowResizeDirection::Top:
-			dir = HTTOP;
-			break;
-		case WindowResizeDirection::TopRight:
-			dir = HTTOPRIGHT;
-			break;
-		case WindowResizeDirection::Right:
-			dir = HTRIGHT;
-			break;
-		case WindowResizeDirection::BottomRight:
-			dir = HTBOTTOMRIGHT;
-			break;
-		case WindowResizeDirection::Bottom:
-			dir = HTBOTTOM;
-			break;
-		case WindowResizeDirection::BottomLeft:
-			dir = HTBOTTOMLEFT;
-			break;
-		}
-
-		SendMessage(mHWnd, WM_SYSCOMMAND, SC_SIZE + 8, 0 );
-		//SetCapture(mHWnd);
-		//SendMessage(mHWnd, WM_NCLBUTTONDOWN, dir, 0);
-		HACK_SendLMBUpEvent();
-		//ReleaseCapture();
-	}
-
-	void D3D11RenderWindow::endResize()
-	{
-
-	}
-
-	void D3D11RenderWindow::startMove()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		SendMessage(mHWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
-		HACK_SendLMBUpEvent();
-	}
-
-	void D3D11RenderWindow::endMove()
-	{
-
-	}
-
 	void D3D11RenderWindow::_windowMovedOrResized()
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 0 - 6
CamelotD3D9Renderer/Include/CmD3D9RenderWindow.h

@@ -108,12 +108,6 @@ namespace CamelotFramework
 		 */
 		Int2 windowToScreenPos(const Int2& windowPos) const;
 
-		void startResize(WindowResizeDirection direction);
-		void endResize();
-
-		void startMove();
-		void endMove();
-
 		/**
 		 * @copydoc RenderWindow::_windowMovedOrResized
 		 */

+ 0 - 65
CamelotD3D9Renderer/Source/CmD3D9RenderWindow.cpp

@@ -38,16 +38,6 @@ THE SOFTWARE.
 
 namespace CamelotFramework
 {
-	// HACK: During the move/resize modal loop no mouse messages will be posted, which means we will
-	// never receive a "mouse up" event, even though user had to release the mouse to stop the loop. But our GUI system
-	// relies on mouse down being followed by mouse up otherwise things end start to break a bit. So here we simulate 
-	// the mouse release. 
-	// Note: This is possible because SendMessage won't return until user releases the mouse and modal loop is done.
-	void HACK_SendLMBUpEvent()
-	{
-		gInput().simulateButtonUp(BC_MOUSE_LEFT);
-	}
-
 	D3D9RenderWindow::D3D9RenderWindow(const RENDER_WINDOW_DESC& desc, HINSTANCE instance)
         : RenderWindow(desc), mInstance(instance), mIsDepthBuffered(true)  
 	{
@@ -497,61 +487,6 @@ namespace CamelotFramework
 		mDevice->copyContentsToMemory(this, dst, buffer);
 	}
 
-	void D3D9RenderWindow::startResize(WindowResizeDirection direction)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		WPARAM dir = HTLEFT;
-		switch(direction)
-		{
-		case WindowResizeDirection::Left:
-			dir = HTLEFT;
-			break;
-		case WindowResizeDirection::TopLeft:
-			dir = HTTOPLEFT;
-			break;
-		case WindowResizeDirection::Top:
-			dir = HTTOP;
-			break;
-		case WindowResizeDirection::TopRight:
-			dir = HTTOPRIGHT;
-			break;
-		case WindowResizeDirection::Right:
-			dir = HTRIGHT;
-			break;
-		case WindowResizeDirection::BottomRight:
-			dir = HTBOTTOMRIGHT;
-			break;
-		case WindowResizeDirection::Bottom:
-			dir = HTBOTTOM;
-			break;
-		case WindowResizeDirection::BottomLeft:
-			dir = HTBOTTOMLEFT;
-			break;
-		}
-
-		SendMessage(mHWnd, WM_NCLBUTTONDOWN, dir, 0);
-		HACK_SendLMBUpEvent();
-	}
-
-	void D3D9RenderWindow::endResize()
-	{
-
-	}
-
-	void D3D9RenderWindow::startMove()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		SendMessage(mHWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
-		HACK_SendLMBUpEvent();
-	}
-
-	void D3D9RenderWindow::endMove()
-	{
-
-	}
-
 	void D3D9RenderWindow::_windowMovedOrResized()
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 0 - 6
CamelotGLRenderer/Include/CmWin32Window.h

@@ -113,12 +113,6 @@ namespace CamelotFramework
 		 */
 		void _windowMovedOrResized(void);
 
-		void startResize(WindowResizeDirection direction);
-		void endResize();
-
-		void startMove();
-		void endMove();
-
 		HWND _getWindowHandle() const { return mHWnd; }
 		HDC _getHDC() const { return mHDC; }
 		

+ 0 - 65
CamelotGLRenderer/Source/CmWin32Window.cpp

@@ -41,16 +41,6 @@ THE SOFTWARE.
 
 namespace CamelotFramework 
 {
-	// HACK: During the move/resize modal loop no mouse messages will be posted, which means we will
-	// never receive a "mouse up" event, even though user had to release the mouse to stop the loop. But our GUI system
-	// relies on mouse down being followed by mouse up otherwise things end start to break a bit. So here we simulate 
-	// the mouse release. 
-	// Note: This is possible because SendMessage won't return until user releases the mouse and modal loop is done.
-	void HACK_SendLMBUpEvent()
-	{
-		gInput().simulateButtonUp(BC_MOUSE_LEFT);
-	}
-
 	#define _MAX_CLASS_NAME_ 128
 
 	Win32Window::Win32Window(const RENDER_WINDOW_DESC& desc, Win32GLSupport &glsupport):
@@ -745,61 +735,6 @@ namespace CamelotFramework
 		}
 	}
 
-	void Win32Window::startResize(WindowResizeDirection direction)
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		WPARAM dir = HTLEFT;
-		switch(direction)
-		{
-		case WindowResizeDirection::Left:
-			dir = HTLEFT;
-			break;
-		case WindowResizeDirection::TopLeft:
-			dir = HTTOPLEFT;
-			break;
-		case WindowResizeDirection::Top:
-			dir = HTTOP;
-			break;
-		case WindowResizeDirection::TopRight:
-			dir = HTTOPRIGHT;
-			break;
-		case WindowResizeDirection::Right:
-			dir = HTRIGHT;
-			break;
-		case WindowResizeDirection::BottomRight:
-			dir = HTBOTTOMRIGHT;
-			break;
-		case WindowResizeDirection::Bottom:
-			dir = HTBOTTOM;
-			break;
-		case WindowResizeDirection::BottomLeft:
-			dir = HTBOTTOMLEFT;
-			break;
-		}
-
-		SendMessage(mHWnd, WM_NCLBUTTONDOWN, dir, 0);
-		HACK_SendLMBUpEvent();
-	}
-
-	void Win32Window::endResize()
-	{
-
-	}
-
-	void Win32Window::startMove()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		SendMessage(mHWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
-		HACK_SendLMBUpEvent();
-	}
-
-	void Win32Window::endMove()
-	{
-
-	}
-
 	void Win32Window::_windowMovedOrResized()
 	{
 		if (!mHWnd || IsIconic(mHWnd))

+ 10 - 28
EditorWindowDock.txt

@@ -1,44 +1,26 @@
 Add icons to drag and drop - There's a built-in windows icon for this. I think. Although solution that accepts custom cursors is probably better longterm. (Special class BuiltinCursors?)
+ - Drag and drop manager currently ignores the provided icon, but it should use it as a cursor
 
-end drag doesn't get called unless mouse is released over a window
- - Capture mouse on start drag (SetCapture, and release with ReleaseCapture)
- - End drag should be handled by GUIManager, but if it doesn't process it DragAndDrop manager should check if mouse was released, and
-   release capture and activate end drag callback
+Fix an issue where drag and dropping a window for the second times causes an exception
 
 Add highlight to WindowMover so I can know when I'm mousing over it with a dragged window in hand
+Ensure that dropping a window onto a mover will actually dock it properly
 
-Reopening the window I can see the update takes a few frames. This shouldn't be the case.
+Change WindowMover to GUIToggle since move functionality has been removed from it.
 
-Drag and drop manager currently ignores the provided icon, but it should use it as a cursor
+Actually set up client areas for resize and move
+ - Figure out how to deal with Cursor change in WindowFrame and non-client areas (which will likely be done in a parent class)
+   - Possibly add two different types of client areas, for move and resize. Then I can keep resize in WindowFrame and keep move in TitleBar.
+
+Get rid of the GUIManager mouseUp hack when I ensure resize/move using non client areas work
 
 Prevent docking if available size is less than 20 pixels, otherwise there might be some weirdness
 
 GUIViewport:
- - MAJOR TODO - GUIViewport updateRenderElementsInternal only gets called when contents change, but viewport should update even if 
+ - TODO - GUIViewport updateRenderElementsInternal only gets called when contents change, but viewport should update even if 
     only its offset changes (normally that just marks the mesh as modified, which doesn't result in a call to updateRenderElementsInternal)
 	- UPDATE: I don't use GUIViewport anymore
 
-------------------------
-
-Get rid of resize hacks:
- - 	In CmWin32Window (and probably same for DX9 and DX11)
-	// HACK: During the move/resize modal loop no mouse messages will be posted, which means we will
-	// never receive a "mouse up" event, even though user had to release the mouse to stop the loop. But our GUI system
-	// relies on mouse down being followed by mouse up otherwise things end start to break a bit. So here we simulate 
-	// the mouse release. 
-	// Note: This is possible because SendMessage won't return until user releases the mouse and modal loop is done.
-	void HACK_SendLMBUpEvent()
-	{
-		gInput().simulateButtonUp(BC_MOUSE_LEFT);
-	}
- - Hack from GUIManager (related to resize and mouse up event)
-
-Also try to get rid of start/end move/resize
-
-Calling Set/Release capture on sim thread probably wont work. Create custom, and send messages instead
-Add Platform::onMouseCaptureLost
-
-
 ------------------------
 
 Other things to remember:

+ 0 - 2
TODO.txt

@@ -6,8 +6,6 @@ MAJOR ISSUE: writeSubresource/readSubresoure doesn't require a shared ptr to Gpu
   - When fixed, make sure I remove blocking calls after writeSubresource where they're not needed (GUIManager for example)
 I call waitUntilLoaded too many times. Sometimes 5-6 times in a single function. Each of those calls will be extremely slow.
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
- - Resizing from the top doesn't work
- - Resizing from the left actually resizes the right side
  - 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