Jelajahi Sumber

GuiFrameSetCtrl Phase 2 Complete

With this code, windows within the frame set can now be dragged out of the frame set so that they become floating windows. Floating windows (with a back-most sibling that's a frame set) can be dragged into the frame set again.
Peter Robinson 2 tahun lalu
induk
melakukan
b4b8af0ba2

+ 32 - 0
editor/EditorCore/Themes/BaseTheme/BaseTheme.cs

@@ -68,6 +68,7 @@ function BaseTheme::onAdd(%this)
 	%this.makeTextDisplayProfile();
 	%this.makeSubListProfile();
 	%this.makeGuiEditorProfile();
+	%this.makeFrameSetProfile();
 }
 
 function BaseTheme::init(%this)
@@ -2013,6 +2014,9 @@ function BaseTheme::makeGuiEditorProfile(%this)
 	%border = new GuiBorderProfile()
 	{
 		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+
 		borderColor = %this.color1; //Used for a single selected nut without key focus
 		borderColorHL = %this.color1; //Used for a multiple selected nuts without key focus
 		borderColorSL = %this.color1; //Used for nuts if the editor has key focus
@@ -2037,7 +2041,10 @@ function BaseTheme::makeGuiEditorProfile(%this)
 		align = "center";
 		vAlign = "middle";
 	};
+}
 
+function BaseTheme::makeFrameSetProfile(%this)
+{
 	%this.frameSetProfile = new GuiControlProfile()
 	{
 		fillColor = %this.adjustValue(%this.color1, 10); 
@@ -2050,6 +2057,31 @@ function BaseTheme::makeGuiEditorProfile(%this)
 		tab = false;
 		canKeyFocus = true;
 	};
+
+	%borderProfile = new GuiBorderProfile()
+	{
+		border = 2;
+		borderHL = 2;
+		borderSL = 8;
+
+		borderColor = %this.color4;
+		borderColorHL = %this.color5;
+		borderColorSL = %this.setAlpha(%this.color5, 150);
+
+		padding = 4;
+		paddingHL = 4;
+		paddingSL = 4;
+		paddingNA = 4;
+	};
+
+	%this.dropButtonProfile = new GuiControlProfile()
+	{
+		fillColor = %this.adjustValue(%this.color1, 10); 
+		fillColorHL = %this.color2; 
+		fillColorSL = %this.setAlpha(%this.color4, 50); 
+
+		borderDefault = %borderProfile;
+	};
 }
 
 //Positive values are brighter, negative are darker

+ 3 - 2
editor/GuiEditor/GuiEditor.cs

@@ -42,6 +42,7 @@ function GuiEditor::create( %this )
         DividerThickness = 6;
 	};
     ThemeManager.setProfile(%this.content, "frameSetProfile");
+    ThemeManager.setProfile(%this.content, "dropButtonProfile", "dropButtonProfile");
     %this.guiPage.add(%this.content);
 
     %idList = %this.content.createHorizontalSplit(1);
@@ -83,7 +84,7 @@ function GuiEditor::create( %this )
         canClose = false;
         canMinimize = true;
         canMaximize = false;
-        resizeWidth = false;
+        resizeWidth = true;
         resizeHeight = true;
     };
     ThemeManager.setProfile(%this.inspectorWindow, "windowProfile");
@@ -124,7 +125,7 @@ function GuiEditor::create( %this )
         canClose = false;
         canMinimize = true;
         canMaximize = false;
-        resizeWidth = false;
+        resizeWidth = true;
         resizeHeight = true;
     };
     ThemeManager.setProfile(%this.ctrlListWindow, "windowProfile");

+ 2 - 2
editor/GuiEditor/scripts/GuiEditorInspectorWindow.cs

@@ -7,7 +7,7 @@ function GuiEditorInspectorWindow::onAdd(%this)
 		HorizSizing="width";
 		VertSizing="height";
 		Position="0 0";
-		Extent="352 355";
+		Extent="352 354";
 		hScrollBar="alwaysOff";
 		vScrollBar="alwaysOn";
 		constantThumbHeight="0";
@@ -26,7 +26,7 @@ function GuiEditorInspectorWindow::onAdd(%this)
 		HorizSizing="width";
 		VertSizing="height";
 		Position="0 0";
-		Extent="338 355";
+		Extent="338 354";
 		FieldCellSize="288 40";
 		ControlOffset="10 18";
 		ConstantThumbHeight=false;

+ 304 - 21
engine/source/gui/containers/guiFrameSetCtrl.cc

@@ -24,13 +24,31 @@
 #include "console/console.h"
 #include "gui/containers/guiFrameSetCtrl.h"
 #include "gui/guiDefaultControlRender.h"
+#include "gui/guiCanvas.h"
+#include "gui/containers/guiWindowCtrl.h"
 
 #include "guiFrameSetCtrl_ScriptBinding.h"
 
+void GuiFrameSetCtrl::Frame::deleteChildren()
+{
+	if (child1)
+	{
+		child1->deleteChildren();
+		delete child1;
+	}
+	if (child2)
+	{
+		child2->deleteChildren();
+		delete child2;
+	}
+}
+
 void GuiFrameSetCtrl::Frame::resize(const Point2I& newPosition, const Point2I& newExtent)
 {
 	const S32 minSize = owner->minSize;
 	extent.set(newExtent.x, newExtent.y);
+	localPosition.set(newPosition.x, newPosition.y);
+	sizeInsertButtons(newPosition, newExtent);
 	if (control)
 	{
 		if (control->mMinExtent.x > minSize || control->mMinExtent.y > minSize)
@@ -78,7 +96,7 @@ void GuiFrameSetCtrl::Frame::resize(const Point2I& newPosition, const Point2I& n
 
 		Point2I ext1 = Point2I(x1, y1);
 		Point2I ext2 = Point2I(x2, y2);
-		Point2I pos2 = isVertical ? Point2I(newPosition.x, y1 + owner->mDividerThickness) : Point2I(x1 + owner->mDividerThickness, newPosition.y);
+		Point2I pos2 = isVertical ? Point2I(newPosition.x, newPosition.y + y1 + owner->mDividerThickness) : Point2I(newPosition.x + x1 + owner->mDividerThickness, newPosition.y);
 
 		if(isVertical)
 		{
@@ -94,6 +112,29 @@ void GuiFrameSetCtrl::Frame::resize(const Point2I& newPosition, const Point2I& n
 	}
 }
 
+void GuiFrameSetCtrl::Frame::sizeInsertButtons(const Point2I& newPosition, const Point2I& newExtent)
+{
+	const U32 size = 40;
+	const U32 gutter = 10;
+
+	hasLeftRightButtons = false;
+	hasTopBottomButtons = false;
+
+	if (newExtent.x > (4 * (size + gutter)))
+	{
+		hasLeftRightButtons = true;
+		mLeftButtonRect = RectI(newPosition.x + gutter, newPosition.y + ((newExtent.y - size) / 2), size, size);
+		mRightButtonRect = RectI(newPosition.x + newExtent.x - (gutter + size), newPosition.y + ((newExtent.y - size) / 2), size, size);
+	}
+
+	if (newExtent.y > (4 * (size + gutter)))
+	{
+		hasTopBottomButtons = true;
+		mTopButtonRect = RectI(newPosition.x + ((newExtent.x - size) / 2), newPosition.y + gutter, size, size);
+		mBottomButtonRect = RectI(newPosition.x + ((newExtent.x - size) / 2), newPosition.y + newExtent.y - (gutter + size), size, size);
+	}
+}
+
 GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrame(const S32 frameID)
 {
 	if (id == frameID)
@@ -157,6 +198,48 @@ GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findHitDivider(const Point2I& po
 	return nullptr;
 }
 
+GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrameWithCtrl(GuiControl* ctrl)
+{
+	if (ctrl == control)
+	{
+		return this;
+	}
+	else if(child1 && child2)
+	{
+		Frame* attempt = child1->findFrameWithCtrl(ctrl);
+		return attempt ? attempt : child2->findFrameWithCtrl(ctrl);
+	}
+	return nullptr;
+}
+
+GuiFrameSetCtrl::Frame* GuiFrameSetCtrl::Frame::findFrameWithPoint(const Point2I& point)
+{
+	//Point is local to the frame.
+	if (control)
+	{
+		return this;
+	}
+	if (child1 && child2)
+	{
+		S32 x = point.x;
+		S32 y = point.y;
+
+		Point2I pos2 = isVertical ? Point2I(x, child1->extent.y + owner->mDividerThickness) : Point2I(child1->extent.x + owner->mDividerThickness, y);
+
+
+		if ((isVertical && y < child1->extent.y) || (!isVertical && x < child1->extent.x))
+		{
+			return child1->findFrameWithPoint(point);
+		}
+		else if ((isVertical && y > pos2.y && y < (pos2.y + child2->extent.y)) || (!isVertical && x > pos2.x && x < (pos2.x + child2->extent.x)))
+		{
+			Point2I pt = Point2I(x - pos2.x, y - pos2.y);
+			return child2->findFrameWithPoint(pt);
+		}
+	}
+	return nullptr;//This will happen if the mouse is over a divider.
+}
+
 
 //------------------------------------------------------------------------------
 
@@ -183,10 +266,18 @@ GuiFrameSetCtrl::GuiFrameSetCtrl()
 	mEaseTimeFillColorHL = 500;
 	mEaseTimeFillColorSL = 1000;
 
+	mDropButtonProfile = NULL;
+	setField("dropButtonProfile", "GuiButtonProfile");
+
 	mLeftRightCursor = NULL;
 	mUpDownCursor = NULL;
 }
 
+GuiFrameSetCtrl::~GuiFrameSetCtrl()
+{
+	mRootFrame.deleteChildren();
+}
+
 //------------------------------------------------------------------------------
 
 void GuiFrameSetCtrl::initPersistFields()
@@ -194,6 +285,7 @@ void GuiFrameSetCtrl::initPersistFields()
 	Parent::initPersistFields();
 
 	addField("DividerThickness", TypeS32, Offset(mDividerThickness, GuiFrameSetCtrl));
+	addField("dropButtonProfile", TypeGuiProfile, Offset(mDropButtonProfile, GuiFrameSetCtrl));
 	addField("leftRightCursor", TypeGuiCursor, Offset(mLeftRightCursor, GuiFrameSetCtrl));
 	addField("upDownCursor", TypeGuiCursor, Offset(mUpDownCursor, GuiFrameSetCtrl));
 }
@@ -205,6 +297,9 @@ bool GuiFrameSetCtrl::onWake()
 	if (!Parent::onWake())
 		return false;
 
+	if (mDropButtonProfile != NULL)
+		mDropButtonProfile->incRefCount();
+
 	return true;
 }
 
@@ -213,6 +308,9 @@ bool GuiFrameSetCtrl::onWake()
 void GuiFrameSetCtrl::onSleep()
 {
 	Parent::onSleep();
+
+	if (mDropButtonProfile != NULL)
+		mDropButtonProfile->decRefCount();
 }
 
 //------------------------------------------------------------------------------
@@ -289,15 +387,49 @@ void GuiFrameSetCtrl::onChildAdded(GuiControl* child)
 
 	Parent::onChildAdded(child);
 
-	Frame* frame = mRootFrame.findEmptyFrame();
-	if(frame)
+	Frame* frame = mRootFrame.findFrameWithCtrl(child);
+	if(!frame)
 	{
-		frame->control = child;
+		Frame* emptyFrame = mRootFrame.findEmptyFrame();
+		if(emptyFrame)
+		{
+			emptyFrame->control = child;
+		}
 	}
+	resize(getPosition(), getExtent());
 }
 
-void GuiFrameSetCtrl::onChildRemoved(SimObject* child)
+void GuiFrameSetCtrl::onChildRemoved(GuiControl* child)
 {
+	Frame* frame = mRootFrame.findFrameWithCtrl(child);
+
+	if (frame && frame == &mRootFrame)
+	{
+		mRootFrame.control = nullptr;
+	}
+	else if(frame)
+	{
+		//Remove the frame from the heirarchy
+		Frame* frameParent = frame->parent;
+		Frame* frameTwin = frame->twin();
+
+		frameParent->control = frameTwin->control;
+		frameParent->child1 = frameTwin->child1;
+		frameParent->child2 = frameTwin->child2;
+		if (frameParent->child1)
+		{
+			frameParent->child1->parent = frameParent;
+		}
+		if (frameParent->child2)
+		{
+			frameParent->child2->parent = frameParent;
+		}
+		frameParent->isVertical = frameTwin->isVertical;
+
+		delete frame;
+		delete frameTwin;
+	}
+
 	resize(getPosition(), getExtent());
 }
 
@@ -325,30 +457,41 @@ Point2I GuiFrameSetCtrl::splitFrame(S32 frameID, bool isVertical)
 
 	if(frame)
 	{
-		if (!frame->child1 && !frame->child2)
-		{
-			GuiControl* ctrl = frame->control;
-			frame->child1 = new GuiFrameSetCtrl::Frame(this, frame);
-			frame->child2 = new GuiFrameSetCtrl::Frame(this, frame);
-
-			frame->control = nullptr;
-			frame->child1->control = ctrl;
-			frame->child1->id = ++mNextFrameID;
-			frame->child2->id = ++mNextFrameID;
-			frame->child1->isAnchored = true;
-			frame->child2->isAnchored = false;
-		}
-	
-		frame->isVertical = isVertical;
-		return Point2I(static_cast<S32>(frame->child1->id), static_cast<S32>(frame->child2->id));
+		splitFrame(frame, isVertical ? GuiDirection::Up : GuiDirection::Left);
+		return Point2I(frame->child1 ? static_cast<S32>(frame->child1->id) :  0, frame->child2 ? static_cast<S32>(frame->child2->id) : 0);
 	}
 	return Point2I::Zero;
 }
 
+void GuiFrameSetCtrl::splitFrame(GuiFrameSetCtrl::Frame* frame, GuiDirection direction)
+{
+	//The existing control, if any, is moved to the new frame in the direction and anchored. The frame oposite is left empty.
+	if (!frame->child1 && !frame->child2)
+	{
+		GuiControl* ctrl = frame->control;
+		frame->child1 = new GuiFrameSetCtrl::Frame(this, frame);
+		frame->child2 = new GuiFrameSetCtrl::Frame(this, frame);
+
+		frame->control = nullptr;
+		frame->child1->control = direction == GuiDirection::Left || direction == GuiDirection::Up ? ctrl : nullptr;
+		frame->child2->control = direction == GuiDirection::Right || direction == GuiDirection::Down ? ctrl : nullptr;
+		frame->child1->id = ++mNextFrameID;
+		frame->child2->id = ++mNextFrameID;
+		frame->child1->isAnchored = direction == GuiDirection::Left || direction == GuiDirection::Up;
+		frame->child2->isAnchored = direction == GuiDirection::Right || direction == GuiDirection::Down;
+	}
+
+	frame->isVertical = direction == GuiDirection::Up || direction == GuiDirection::Down;
+}
+
 void GuiFrameSetCtrl::anchorFrame(S32 frameID)
 {
 	Frame* frame = mRootFrame.findFrame(frameID);
+	anchorFrame(frame);
+}
 
+void GuiFrameSetCtrl::anchorFrame(GuiFrameSetCtrl::Frame* frame)
+{
 	if (frame && frame != &mRootFrame)//The root frame has no twin and can't be anchored.
 	{
 		frame->isAnchored = true;
@@ -507,4 +650,144 @@ void GuiFrameSetCtrl::getCursor(GuiCursor*& cursor, bool& showCursor, const GuiE
 			cursor = mLeftRightCursor;
 		}
 	}
+}
+
+void GuiFrameSetCtrl::renderDropOptions(GuiWindowCtrl* window)
+{
+	Point2I cursorPt = Point2I(0, 0);
+	GuiCanvas* root = getRoot();
+	if (root)
+	{
+		cursorPt = globalToLocalCoord(root->getCursorPos());
+		cursorPt.x = getMin(getMax(0, cursorPt.x), mRootFrame.extent.x);
+		cursorPt.y = getMin(getMax(0, cursorPt.y), mRootFrame.extent.y);
+	}
+
+	Frame* frame = mRootFrame.findFrameWithPoint(cursorPt);
+	if (frame)
+	{
+		ColorI fillColor = mProfile->getFillColor(SelectedState);
+		fillColor.alpha = 50;
+		const U32 width = getMax(minSize, getMin(frame->extent.x / 2, window->mBounds.extent.x));
+		const U32 height = getMax(minSize, getMin(frame->extent.y / 2, window->mBounds.extent.y));
+
+		if (frame->hasLeftRightButtons)
+		{
+			Point2I fillExt = Point2I(width, frame->extent.y);
+			renderDropButton(frame, frame->mLeftButtonRect, cursorPt, frame->localPosition, fillExt, GuiDirection::Left);
+			renderDropButton(frame, frame->mRightButtonRect, cursorPt, Point2I(frame->localPosition.x + frame->extent.x - width, frame->localPosition.y), fillExt, GuiDirection::Right);
+		}
+
+		if (frame->hasTopBottomButtons)
+		{
+			Point2I fillExt = Point2I(frame->extent.x, height);
+			renderDropButton(frame, frame->mTopButtonRect, cursorPt, frame->localPosition, fillExt, GuiDirection::Up);
+			renderDropButton(frame, frame->mBottomButtonRect, cursorPt, Point2I(frame->localPosition.x, frame->localPosition.y + frame->extent.y - height), fillExt, GuiDirection::Down);
+		}
+	}
+}
+
+void GuiFrameSetCtrl::renderDropButton(const GuiFrameSetCtrl::Frame* frame, const RectI& buttonRect, const Point2I& cursorPt, const Point2I& fillPos, const Point2I& fillExt, GuiDirection direction)
+{
+	GuiControlState state = NormalState;
+	if (buttonRect.pointInRect(cursorPt))
+	{
+		state = HighlightState;
+		RectI rect = RectI(fillPos, fillExt);
+		rect.point = localToGlobalCoord(rect.point);
+		setUpdateRegion(rect.point, rect.extent);
+		renderUniversalRect(rect, mDropButtonProfile, SelectedState);
+	}
+	RectI globalButtonRect = RectI(localToGlobalCoord(buttonRect.point), buttonRect.extent);
+	renderUniversalRect(globalButtonRect, mDropButtonProfile, state);
+
+	dglSetBitmapModulation(getFontColor(mDropButtonProfile, state));
+	ColorI triColor = getFontColor(mDropButtonProfile, state);
+	renderTriangleIcon(globalButtonRect, triColor, direction, 10);
+}
+
+void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
+{
+	Point2I cursorPt = Point2I(0, 0);
+	GuiCanvas* root = getRoot();
+	if (root)
+	{
+		cursorPt = globalToLocalCoord(root->getCursorPos());
+		cursorPt.x = getMin(getMax(0, cursorPt.x), mRootFrame.extent.x);
+		cursorPt.y = getMin(getMax(0, cursorPt.y), mRootFrame.extent.y);
+	}
+	Frame* frame = mRootFrame.findFrameWithPoint(cursorPt);
+
+	if (frame)
+	{
+		const U32 width = getMax(minSize, getMin(frame->extent.x / 2, window->mBounds.extent.x));
+		const U32 height = getMax(minSize, getMin(frame->extent.y / 2, window->mBounds.extent.y));
+
+		bool hitButton = false;
+		if (frame->mLeftButtonRect.pointInRect(cursorPt))
+		{
+			splitFrame(frame, GuiDirection::Right);//This existing control goes right, the new window will go left.
+			anchorFrame(frame->child1);
+			frame->child1->control = window;
+			frame->child1->extent = Point2I(width, frame->extent.y);
+			hitButton = true;
+		}
+		else if (frame->mRightButtonRect.pointInRect(cursorPt))
+		{
+			splitFrame(frame, GuiDirection::Left);
+			anchorFrame(frame->child2);
+			frame->child2->control = window;
+			frame->child2->extent = Point2I(width, frame->extent.y);
+			hitButton = true;
+		}
+		else if (frame->mTopButtonRect.pointInRect(cursorPt))
+		{
+			splitFrame(frame, GuiDirection::Down);
+			anchorFrame(frame->child1);
+			frame->child1->control = window;
+			frame->child1->extent = Point2I(frame->extent.x, height);
+			hitButton = true;
+		}
+		else if (frame->mBottomButtonRect.pointInRect(cursorPt))
+		{
+			splitFrame(frame, GuiDirection::Up);
+			anchorFrame(frame->child2);
+			frame->child2->control = window;
+			frame->child2->extent = Point2I(frame->extent.x, height);
+			hitButton = true;
+		}
+
+		if (hitButton)
+		{
+			addObject(window);
+		}
+	}
+}
+
+void GuiFrameSetCtrl::setDropButtonProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiFrameSetCtrl::setDropButtonProfile: invalid content profile");
+	if (prof == mDropButtonProfile)
+		return;
+	if (mAwake)
+		mDropButtonProfile->decRefCount();
+	mDropButtonProfile = prof;
+	if (mAwake)
+		mDropButtonProfile->incRefCount();
+}
+
+void GuiFrameSetCtrl::setControlLeftRightCursor(GuiCursor* cursor)
+{
+	AssertFatal(cursor, "GuiFrameSetCtrl::setControlLeftRightCursor: invalid cursor");
+	if (cursor == mLeftRightCursor)
+		return;
+	mLeftRightCursor = cursor;
+}
+
+void GuiFrameSetCtrl::setControlUpDownCursor(GuiCursor* cursor)
+{
+	AssertFatal(cursor, "GuiFrameSetCtrl::setControlUpDownCursor: invalid cursor");
+	if (cursor == mUpDownCursor)
+		return;
+	mUpDownCursor = cursor;
 }

+ 29 - 5
engine/source/gui/containers/guiFrameSetCtrl.h

@@ -12,6 +12,7 @@
 #include "graphics/dgl.h"
 #include "console/console.h"
 #include "console/consoleTypes.h"
+#include "gui/containers/guiWindowCtrl.h"
 
 class GuiFrameSetCtrl : public GuiEasingSupport
 {
@@ -26,21 +27,32 @@ private:
 	GuiCursor* mLeftRightCursor;
 	GuiCursor* mUpDownCursor;
 
+	GuiControlProfile* mDropButtonProfile; //Used to render a drop button (the buttons that appear on frames when dragging a window).
+
 public:
 	class Frame
 	{
 	public:
-		Frame() : owner(nullptr), parent(nullptr), child1(nullptr), child2(nullptr),
-			control(nullptr), isVertical(true), id(1), extent(Point2I(100, 100)), dividerRect(RectI()) { }
+		Frame() : Frame(nullptr, nullptr) { }
 		Frame(GuiFrameSetCtrl* theOwner, Frame* theParent) : owner(theOwner), parent(theParent), child1(nullptr), child2(nullptr), 
-			control(nullptr), isVertical(true), id(1), extent(Point2I(100, 100)), dividerRect(RectI()) { }
+			control(nullptr), isVertical(true), id(1), extent(Point2I(100, 100)), dividerRect(RectI()),
+			localPosition(Point2I(0, 0)), mLeftButtonRect(RectI()), mRightButtonRect(RectI()),
+			mTopButtonRect(RectI()), mBottomButtonRect(RectI()), isAnchored(true), hasLeftRightButtons(false), hasTopBottomButtons(false) { }
 		virtual ~Frame() { }
+		void deleteChildren();
 
 		bool isVertical;
 		U32 id;
 		Point2I extent;
+		Point2I localPosition;
 		bool isAnchored;
 		RectI dividerRect;
+		RectI mLeftButtonRect;
+		RectI mRightButtonRect;
+		RectI mTopButtonRect;
+		RectI mBottomButtonRect;
+		bool hasLeftRightButtons;
+		bool hasTopBottomButtons;
 
 		GuiFrameSetCtrl* owner;
 		Frame* parent;
@@ -50,10 +62,13 @@ public:
 		GuiControl* control;
 
 		void resize(const Point2I& newPosition, const Point2I& newExtent);
+		void sizeInsertButtons(const Point2I& newPosition, const Point2I& newExtent);
 		Frame* findFrame(const S32 frameID);
 		Frame* findEmptyFrame();
 		Frame* twin();
 		Frame* findHitDivider(const Point2I& position);
+		Frame* findFrameWithCtrl(GuiControl* ctrl);
+		Frame* findFrameWithPoint(const Point2I& point);
 	};
 	Frame mRootFrame;
 	Frame* mHitDivider;
@@ -66,22 +81,27 @@ private:
 
 public:
 	GuiFrameSetCtrl();
+	~GuiFrameSetCtrl();
 	static void initPersistFields();
 	
 	bool onAdd();
 	virtual void parentResized(const Point2I& oldParentExtent, const Point2I& newParentExtent);
 	void resize(const Point2I& newPosition, const Point2I& newExtent);
-	//void childResized(GuiControl *child);
 	void inspectPostApply();
 	bool onWake();
 	void onSleep();
 	void onChildAdded(GuiControl* child);
-	void onChildRemoved(SimObject* child);
+	void onChildRemoved(GuiControl* child);
 	void childResized(GuiControl* child);
 	void childMoved(GuiControl* child);
 	void childrenReordered();
+	void renderDropOptions(GuiWindowCtrl* window);
+	void renderDropButton(const GuiFrameSetCtrl::Frame* frame, const RectI& buttonRect, const Point2I& cursorPt, const Point2I& fillPos, const Point2I& fillExt, GuiDirection direction);
+	void handleDropButtons(GuiWindowCtrl* window);
 
 	Point2I splitFrame(S32 frameID, bool isVertical);
+	void splitFrame(GuiFrameSetCtrl::Frame* frame, GuiDirection direction);
+	void anchorFrame(GuiFrameSetCtrl::Frame* frame);
 	void anchorFrame(S32 frameID);
 	void setFrameSize(S32 frameID, S32 size);
 	void onRender(Point2I offset, const RectI& updateRect);
@@ -91,6 +111,10 @@ public:
 	void onTouchUp(const GuiEvent& event);
 	void getCursor(GuiCursor*& cursor, bool& showCursor, const GuiEvent& lastGuiEvent);
 
+	void setDropButtonProfile(GuiControlProfile* prof);
+	void setControlLeftRightCursor(GuiCursor* cursor);
+	void setControlUpDownCursor(GuiCursor* cursor);
+
 	DECLARE_CONOBJECT(GuiFrameSetCtrl);
 };
 

+ 2 - 2
engine/source/gui/containers/guiGridCtrl.cc

@@ -330,7 +330,7 @@ Point2F GuiGridCtrl::GetGridItemHeight(const S32 totalArea, const S32 maxChainLe
 	return Point2F(1, 1);
 }
 
-void GuiGridCtrl::onChildAdded(GuiControl *child)
+void GuiGridCtrl::onChildAdded(GuiControl* child)
 {
 	//Ensure the child isn't positioned to the center
 	if (child->getHorizSizing() == horizResizeCenter)
@@ -346,7 +346,7 @@ void GuiGridCtrl::onChildAdded(GuiControl *child)
 	Parent::onChildAdded(child);
 }
 
-void GuiGridCtrl::onChildRemoved(SimObject *child)
+void GuiGridCtrl::onChildRemoved(GuiControl* child)
 {
 	resize(getPosition(), getExtent());
 }

+ 2 - 2
engine/source/gui/containers/guiGridCtrl.h

@@ -69,8 +69,8 @@ public:
 	void inspectPostApply();
 	bool onWake();
 	void onSleep();
-	void onChildAdded(GuiControl *child);
-	void onChildRemoved(SimObject *child); 
+	void onChildAdded(GuiControl* child);
+	void onChildRemoved(GuiControl* child);
 	void childResized(GuiControl* child);
 	void childMoved(GuiControl* child);
 	void childrenReordered();

+ 88 - 28
engine/source/gui/containers/guiWindowCtrl.cc

@@ -175,6 +175,12 @@ GuiControl* GuiWindowCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
 
 void GuiWindowCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
 {
+	GuiFrameSetCtrl* frameSet = dynamic_cast<GuiFrameSetCtrl*>(getParent());
+	if (frameSet && !mMinimized && !mMaximized)
+	{
+		mStandardBounds = mBounds;
+		mMaximized = true;
+	}
    Parent::resize(newPosition, newExtent);
 }
 
@@ -254,6 +260,7 @@ void GuiWindowCtrl::onTouchDragged(const GuiEvent &event)
 {
    GuiControl *parent = getParent();
    GuiCanvas *root = getRoot();
+   GuiFrameSetCtrl* frameSet = dynamic_cast<GuiFrameSetCtrl*>(getParent());
    if (! root) return;
 
    curHitRegion = findHitRegion(globalToLocalCoord(event.mousePoint));
@@ -289,6 +296,36 @@ void GuiWindowCtrl::onTouchDragged(const GuiEvent &event)
       }
    }
 
+   if (mMouseMovingWin && frameSet)
+   {
+		const S32 dragDist = 20;
+	   if (mAbs(deltaMousePosition.x) > dragDist || mAbs(deltaMousePosition.y) > dragDist)
+	   {
+			newPosition = parent->localToGlobalCoord(newPosition);
+
+		   //Make the window the front-most child in the grandparent
+		   GuiControl* grandparent = frameSet->getParent();
+		   grandparent->addObject(this);
+		   grandparent->pushObjectToBack(this);
+		   mouseLock();
+
+		   if (mAbs(newPosition.x - mMouseDownPosition.x) > mStandardBounds.extent.x)
+		   {
+			   mMouseDownPosition.x = mOrigBounds.point.x + (mStandardBounds.extent.x / 2);
+			   deltaMousePosition.x = event.mousePoint.x - mMouseDownPosition.x;
+			   newPosition.x = getMax(0, getMin(parent->mBounds.extent.x - mBounds.extent.x, mOrigBounds.point.x + deltaMousePosition.x));
+		   }
+
+		   newPosition = grandparent->globalToLocalCoord(newPosition);
+		   newExtent = mStandardBounds.extent;
+		   mMaximized = false;
+	   }
+	   else
+	   {
+			update = false;
+	   }
+   }
+
    if (update)
    {
       Point2I pos = parent->localToGlobalCoord(getPosition());
@@ -310,13 +347,19 @@ void GuiWindowCtrl::onTouchUp(const GuiEvent &event)
    mouseUnlock();
    setUpdate();
 
-   MoveComplete();
-   ResizeComplete();
-
    GuiControl *parent = getParent();
    if (! parent)
       return;
 
+   GuiFrameSetCtrl* backFrameSet = dynamic_cast<GuiFrameSetCtrl*>((*parent)[0]);
+   if (mMouseMovingWin && backFrameSet)
+   {
+		backFrameSet->handleDropButtons(this);
+   }
+
+   MoveComplete();
+   ResizeComplete();
+
    //see if we take an action
    Point2I localPoint = globalToLocalCoord(event.mousePoint);
    if (closing && mCloseButton.pointInRect(localPoint))
@@ -330,17 +373,7 @@ void GuiWindowCtrl::onTouchUp(const GuiEvent &event)
    {
       if (mMaximized)
       {
-         //resize to the previous position and extent, bounded by the parent
-         resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
-                        getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
-                        mStandardBounds.extent);
-         //set the flag
-         mMaximized = false;
-
-		 if (isMethod("onRestore"))
-		 {
-			 Con::executef(this, 1, "onRestore");
-		 }
+         restore();
       }
       else
       {
@@ -370,17 +403,7 @@ void GuiWindowCtrl::onTouchUp(const GuiEvent &event)
    {
       if (mMinimized)
       {
-         //resize to the previous position and extent, bounded by the parent
-         resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
-                        getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
-                        mStandardBounds.extent);
-         //set the flag
-         mMinimized = false;
-
-		 if (isMethod("onRestore"))
-		 {
-			 Con::executef(this, 1, "onRestore");
-		 }
+         restore();
       }
       else
       {
@@ -450,6 +473,29 @@ void GuiWindowCtrl::onTouchUp(const GuiEvent &event)
 
 }
 
+void GuiWindowCtrl::restore()
+{
+	GuiControl* parent = getParent();
+	if (!parent)
+	{
+		return;
+	}
+
+	//resize to the previous position and extent, bounded by the parent
+	resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
+	getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
+	mStandardBounds.extent);
+
+	//set the flags
+	mMinimized = false;
+	mMaximized = false;
+
+	if (isMethod("onRestore"))
+	{
+		Con::executef(this, 1, "onRestore");
+	}
+}
+
 GuiControl *GuiWindowCtrl::findNextTabable(GuiControl *curResponder, bool firstCall)
 {
    //set the global if this is the first call (directly from the canvas)
@@ -689,12 +735,26 @@ void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect)
 			renderChildControls(offset, contentRectWindow, updateRect);
 		}
 	}
+
+	//Render FrameSet Drop Options
+	GuiControl* parent = getParent();
+	if(!parent)
+	{
+		return;
+	}
+	GuiFrameSetCtrl* backFrameSet = dynamic_cast<GuiFrameSetCtrl*>((*parent)[0]);
+	if (mMouseMovingWin && backFrameSet)
+	{
+		backFrameSet->renderDropOptions(this);
+	}
 }
 
 RectI GuiWindowCtrl::renderButtons(const Point2I &offset, const RectI &contentRect)
 {
 	S32 distanceFromEdge = 0;
 
+	GuiFrameSetCtrl* frameSet = dynamic_cast<GuiFrameSetCtrl*>(getParent());
+
 	if (mCanClose)
 	{
 		GuiControlState state = getRegionCurrentState(Region::CloseButton);
@@ -710,7 +770,7 @@ RectI GuiWindowCtrl::renderButtons(const Point2I &offset, const RectI &contentRe
 		S32 rightSize = (rightProfile) ? rightProfile->getMargin(state) : 0;
 		distanceFromEdge += rightSize;
 	}
-	if (mCanMaximize)
+	if (mCanMaximize && !frameSet)
 	{
 		GuiControlState state = getRegionCurrentState(Region::MaxButton);
 		RectI content = renderButton(contentRect, distanceFromEdge, state, mMaxButtonProfile, Icon::Max);
@@ -725,7 +785,7 @@ RectI GuiWindowCtrl::renderButtons(const Point2I &offset, const RectI &contentRe
 		S32 rightSize = (rightProfile) ? rightProfile->getMargin(state) : 0;
 		distanceFromEdge += rightSize;
 	}
-	if (mCanMinimize)
+	if (mCanMinimize && !frameSet)
 	{
 		GuiControlState state = getRegionCurrentState(Region::MinButton);
 		RectI content = renderButton(contentRect, distanceFromEdge, state, mMinButtonProfile, Icon::Min);
@@ -871,7 +931,7 @@ void GuiWindowCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEve
 	{
 		return;
 	}
-	GuiFrameSetCtrl* frame = static_cast<GuiFrameSetCtrl*>(parent);
+	GuiFrameSetCtrl* frame = dynamic_cast<GuiFrameSetCtrl*>(parent);
 	if (frame)
 	{
 		return;//Resizing doesn't happen when in a frame set.

+ 1 - 0
engine/source/gui/containers/guiWindowCtrl.h

@@ -120,6 +120,7 @@ class GuiWindowCtrl : public GuiControl
 
       GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);
       void resize(const Point2I &newPosition, const Point2I &newExtent);
+	  void restore();
 
 	  void onTouchMove(const GuiEvent &event);
       void onTouchDown(const GuiEvent &event);