2
0
Эх сурвалжийг харах

GuiFrameSetCtrl Phase 3 Complete

With this code, windows can now be pulled out of generated tab books by dragging the tab, turning the tab back into a floating window. When one tab remains the book is destroyed entirely and the remaining tab is returned to a docked window.
Peter Robinson 2 жил өмнө
parent
commit
8d837da099

+ 73 - 10
engine/source/gui/containers/guiFrameSetCtrl.cc

@@ -553,6 +553,19 @@ void GuiFrameSetCtrl::setFrameSize(S32 frameID, S32 size)
 	}
 }
 
+void GuiFrameSetCtrl::onPreRender()
+{
+	SimSet::iterator i;
+	for(i = begin(); i < end(); i++)
+	{
+		GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
+		if (book->mIsFrameSetGenerated && book->size() == 0)
+		{
+			book->deleteObject();
+		}
+	}
+}
+
 void GuiFrameSetCtrl::onRender(Point2I offset, const RectI& updateRect)
 {
 	Parent::onRender(offset, updateRect);
@@ -718,13 +731,18 @@ void GuiFrameSetCtrl::renderDropOptions(GuiWindowCtrl* window)
 			renderDropButton(frame, frame->mBottomButtonRect, cursorPt, Point2I(frame->localPosition.x, frame->localPosition.y + frame->extent.y - height), fillExt, GuiDirection::Down);
 		}
 
-		if (frame->isAnchored || (!frame->control && !frame->child1 && !frame->child2))
+		if (hasCenterButton(frame))
 		{
 			renderDropButton(frame, frame->mCenterButtonRect, cursorPt, frame->localPosition, frame->extent, GuiDirection::Center);
 		}
 	}
 }
 
+bool GuiFrameSetCtrl::hasCenterButton(GuiFrameSetCtrl::Frame* frame)
+{
+	return (frame != &mRootFrame && (frame->isAnchored || (!frame->control && !frame->child1 && !frame->child2)));
+}
+
 void GuiFrameSetCtrl::renderDropButton(const GuiFrameSetCtrl::Frame* frame, const RectI& buttonRect, const Point2I& cursorPt, const Point2I& fillPos, const Point2I& fillExt, GuiDirection direction)
 {
 	GuiControlState state = NormalState;
@@ -773,7 +791,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 		const U32 height = getMax(minSize, getMin(frame->extent.y / 2, window->mBounds.extent.y));
 
 		bool hitButton = false;
-		if (frame->mLeftButtonRect.pointInRect(cursorPt))
+		if (frame->hasLeftRightButtons && frame->mLeftButtonRect.pointInRect(cursorPt))
 		{
 			splitFrame(frame, GuiDirection::Right);//This existing control goes right, the new window will go left.
 			anchorFrame(frame->child1);
@@ -781,7 +799,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 			frame->child1->extent = Point2I(width, frame->extent.y);
 			hitButton = true;
 		}
-		else if (frame->mRightButtonRect.pointInRect(cursorPt))
+		else if (frame->hasLeftRightButtons && frame->mRightButtonRect.pointInRect(cursorPt))
 		{
 			splitFrame(frame, GuiDirection::Left);
 			anchorFrame(frame->child2);
@@ -789,7 +807,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 			frame->child2->extent = Point2I(width, frame->extent.y);
 			hitButton = true;
 		}
-		else if (frame->mTopButtonRect.pointInRect(cursorPt))
+		else if (frame->hasTopBottomButtons && frame->mTopButtonRect.pointInRect(cursorPt))
 		{
 			splitFrame(frame, GuiDirection::Down);
 			anchorFrame(frame->child1);
@@ -797,7 +815,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 			frame->child1->extent = Point2I(frame->extent.x, height);
 			hitButton = true;
 		}
-		else if (frame->mBottomButtonRect.pointInRect(cursorPt))
+		else if (frame->hasTopBottomButtons && frame->mBottomButtonRect.pointInRect(cursorPt))
 		{
 			splitFrame(frame, GuiDirection::Up);
 			anchorFrame(frame->child2);
@@ -805,7 +823,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 			frame->child2->extent = Point2I(frame->extent.x, height);
 			hitButton = true;
 		}
-		else if (frame->mCenterButtonRect.pointInRect(cursorPt))
+		else if (hasCenterButton(frame) && frame->mCenterButtonRect.pointInRect(cursorPt))
 		{
 			if (!frame->control)
 			{
@@ -845,6 +863,7 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 				page->setText(window->getText());
 				page->addObject(window);
 				book->selectPage(window->getText());
+				window->resize(window->getPosition(), window->getExtent());
 			}
 		}
 
@@ -855,6 +874,50 @@ void GuiFrameSetCtrl::handleDropButtons(GuiWindowCtrl* window)
 	}
 }
 
+void GuiFrameSetCtrl::undockWindowFromBook(GuiWindowCtrl* window, GuiTabBookCtrl* book, GuiTabPageCtrl* page)
+{
+	GuiControl* parent = getParent();
+	GuiCanvas* root = getRoot();
+	if (parent && window && book && page && window->mPageDocked && root)
+	{
+		parent->addObject(window);
+		parent->pushObjectToBack(window); 
+		Point2I cursorPt = globalToLocalCoord(root->getCursorPos());
+		
+		window->undockFromPage();
+		window->restore();
+		Point2I newPosition = Point2I(cursorPt.x - (window->getExtent().x / 2), cursorPt.y - (window->getTitleHeight() / 2));
+		Point2I pos = parent->localToGlobalCoord(newPosition);
+		root->addUpdateRegion(pos, window->getExtent());
+		window->resize(newPosition, window->getExtent());
+		GuiEvent event = GuiEvent();
+		event.mousePoint = Point2I(root->getCursorPos());
+		event.mouseClickCount = 1;
+		root->rootScreenTouchUp(event);
+		root->rootScreenTouchDown(event);
+
+		book->removeObject(page);
+		page->deleteObject();
+
+		if (book->size() > 0)
+		{
+			book->calculatePageTabs();
+			book->selectPage(0);
+		}
+
+		if (book->mIsFrameSetGenerated && book->size() == 1)
+		{
+			GuiTabPageCtrl* lastPage = dynamic_cast<GuiTabPageCtrl*>((*book)[0]);
+			GuiWindowCtrl* lastWindow = dynamic_cast<GuiWindowCtrl*>((*lastPage)[0]);
+			GuiFrameSetCtrl::Frame* frame = mRootFrame.findFrameWithCtrl(book);
+			frame->control = lastWindow;
+			addObject(lastWindow);
+			lastPage->deleteObject();
+			lastWindow->undockFromPage();
+		}
+	}
+}
+
 void GuiFrameSetCtrl::setDropButtonProfile(GuiControlProfile* prof)
 {
 	AssertFatal(prof, "GuiFrameSetCtrl::setDropButtonProfile: invalid content profile");
@@ -882,7 +945,7 @@ void GuiFrameSetCtrl::setTabBookProfile(GuiControlProfile* prof)
 	SimSet::iterator i;
 	for (i = begin(); i != end(); i++)
 	{
-		GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
+		GuiTabBookCtrl* book = dynamic_cast<GuiTabBookCtrl*>(*i);
 		if (book && book->mIsFrameSetGenerated)
 		{
 			book->setControlProfile(prof);
@@ -904,7 +967,7 @@ void GuiFrameSetCtrl::setTabProfile(GuiControlProfile* prof)
 	SimSet::iterator i;
 	for (i = begin(); i != end(); i++)
 	{
-		GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
+		GuiTabBookCtrl* book = dynamic_cast<GuiTabBookCtrl*>(*i);
 		if (book && book->mIsFrameSetGenerated)
 		{
 			book->setControlTabProfile(prof);
@@ -926,13 +989,13 @@ void GuiFrameSetCtrl::setTabPageProfile(GuiControlProfile* prof)
 	SimSet::iterator i;
 	for (i = begin(); i != end(); i++)
 	{
-		GuiTabBookCtrl* book = static_cast<GuiTabBookCtrl*>(*i);
+		GuiTabBookCtrl* book = dynamic_cast<GuiTabBookCtrl*>(*i);
 		if (book && book->mIsFrameSetGenerated)
 		{
 			SimSet::iterator j;
 			for (j = begin(); j != end(); j++)
 			{
-				GuiTabPageCtrl* page = static_cast<GuiTabPageCtrl*>(*i);
+				GuiTabPageCtrl* page = dynamic_cast<GuiTabPageCtrl*>(*i);
 				if (page)
 				{
 					page->setControlProfile(prof);

+ 4 - 0
engine/source/gui/containers/guiFrameSetCtrl.h

@@ -13,6 +13,7 @@
 #include "console/console.h"
 #include "console/consoleTypes.h"
 #include "gui/containers/guiWindowCtrl.h"
+#include "gui/containers/guiTabBookCtrl.h"
 
 class GuiFrameSetCtrl : public GuiEasingSupport
 {
@@ -101,14 +102,17 @@ public:
 	void childMoved(GuiControl* child);
 	void childrenReordered();
 	void renderDropOptions(GuiWindowCtrl* window);
+	bool hasCenterButton(GuiFrameSetCtrl::Frame* frame);
 	void renderDropButton(const GuiFrameSetCtrl::Frame* frame, const RectI& buttonRect, const Point2I& cursorPt, const Point2I& fillPos, const Point2I& fillExt, GuiDirection direction);
 	void handleDropButtons(GuiWindowCtrl* window);
+	void undockWindowFromBook(GuiWindowCtrl* window, GuiTabBookCtrl* book, GuiTabPageCtrl* page);
 
 	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 onPreRender();
 	void onRender(Point2I offset, const RectI& updateRect);
 	void onTouchMove(const GuiEvent& event);
 	void onTouchDragged(const GuiEvent& event);

+ 41 - 0
engine/source/gui/containers/guiTabBookCtrl.cc

@@ -30,6 +30,7 @@
 #include "gui/containers/guiScrollCtrl.h"
 #include "gui/editor/guiEditCtrl.h"
 #include "gui/guiDefaultControlRender.h"
+#include "gui/containers/guiFrameSetCtrl.h"
 
 #include "guiTabBookCtrl_ScriptBinding.h"
 
@@ -59,6 +60,8 @@ GuiTabBookCtrl::GuiTabBookCtrl()
    mBounds.extent.set( 400, 300 );
    mPageRect = RectI(0,0,0,0);
    mTabRect = RectI(0,0,0,0);
+   mTabDownPosition = Point2I();
+   mDepressed = false;
 
    mPages.reserve(12);
    mMinTabWidth = 64;
@@ -260,6 +263,10 @@ void GuiTabBookCtrl::onTouchDown(const GuiEvent &event)
     Point2I localMouse = globalToLocalCoord( event.mousePoint );
     if( mTabRect.pointInRect( localMouse ) )
     {
+		mTabDownPosition = event.mousePoint;
+		mDepressed = true;
+		mouseLock();
+
 		Point2I tabLocalMouse = getTabLocalCoord(localMouse);
         GuiTabPageCtrl *tab = findHitTab(tabLocalMouse);
         if( tab != NULL && tab->isActive() )
@@ -293,6 +300,40 @@ void GuiTabBookCtrl::onTouchMove(const GuiEvent &event)
 void GuiTabBookCtrl::onTouchLeave( const GuiEvent &event )
 {
    mHoverTab = NULL;
+   Parent::onTouchLeave(event);
+}
+
+void GuiTabBookCtrl::onTouchDragged(const GuiEvent& event)
+{
+	if (mDepressed && mActivePage && mActivePage->size() > 0)
+	{
+		Point2I deltaMousePosition = event.mousePoint - mTabDownPosition;
+		const S32 dragDist = 20;
+		if (mAbs(deltaMousePosition.x) > dragDist || mAbs(deltaMousePosition.y) > dragDist)
+		{
+			//That's cool, but to transform the tab into window, we need a parent FrameSet and a grandchild that's a docked window.
+			GuiFrameSetCtrl* frameSet = dynamic_cast<GuiFrameSetCtrl*>(getParent());
+			GuiWindowCtrl* window = dynamic_cast<GuiWindowCtrl*>((*mActivePage)[0]);
+			if (frameSet && window && window->mPageDocked)
+			{
+				//We have a winner!!!
+				mDepressed = false;
+				mouseUnlock();
+				frameSet->undockWindowFromBook(window, this, mActivePage);
+				return;
+			}
+		}
+	}
+	Parent::onTouchDragged(event);
+}
+
+void GuiTabBookCtrl::onTouchUp(const GuiEvent& event)
+{
+	if (mDepressed)
+	{
+		mouseUnlock();
+	}
+	Parent::onTouchUp(event);
 }
 
 bool GuiTabBookCtrl::onMouseDownEditor(const GuiEvent &event, Point2I offset)

+ 4 - 0
engine/source/gui/containers/guiTabBookCtrl.h

@@ -93,6 +93,8 @@ private:
    TabPosition             mLastTabPosition; ///< Last known tab position, stored to compare to tabPosition to know when to resize children
    S32                     mFontHeight;      ///< Last known font height
    S32                     mTabWidth;        ///< Current tab width of the first tab
+   Point2I mTabDownPosition; 
+   bool mDepressed;
    
    enum
    {
@@ -243,6 +245,8 @@ private:
    void onTouchDown(const GuiEvent &event);
    void onTouchMove(const GuiEvent &event);
    void onTouchLeave(const GuiEvent &event);
+   void onTouchDragged(const GuiEvent& event);
+   void onTouchUp(const GuiEvent& event);
    virtual bool onMouseDownEditor(const GuiEvent &event, Point2I offset);
    /// @}
 };

+ 22 - 2
engine/source/gui/containers/guiWindowCtrl.cc

@@ -190,16 +190,35 @@ void GuiWindowCtrl::dockToPage()
 	}
 }
 
+void GuiWindowCtrl::undockFromPage()
+{
+	mPageDocked = false;
+	setUpdate();
+	Point2I newExtent = mBounds.extent;
+	Point2I oldExtent = Point2I(newExtent.x, newExtent.y + mTitleHeight);
+	iterator i;
+	for (i = begin(); i != end(); i++)
+	{
+		GuiControl* ctrl = static_cast<GuiControl*>(*i);
+		ctrl->parentResized(oldExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB), newExtent - (ctrl->mRenderInsetLT + ctrl->mRenderInsetRB));
+	}
+}
+
 void GuiWindowCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
 {
 	GuiFrameSetCtrl* frameSet = dynamic_cast<GuiFrameSetCtrl*>(getParent());
-	if (frameSet && !mMinimized && !mMaximized)
+	GuiTabPageCtrl* page = dynamic_cast<GuiTabPageCtrl*>(getParent());
+	GuiTabBookCtrl* book = nullptr;
+	if (page)
+	{
+		book = dynamic_cast<GuiTabBookCtrl*>(page->getParent());
+	}
+	if ((frameSet || (book && book->mIsFrameSetGenerated)) && !mMinimized && !mMaximized)
 	{
 		mStandardBounds = mBounds;
 		mMaximized = true;
 	}
 
-	GuiTabPageCtrl* page = dynamic_cast<GuiTabPageCtrl*>(getParent());
 	if (page && mPageDocked)
 	{
 		Parent::resize(Point2I::Zero, page->getExtent());
@@ -218,6 +237,7 @@ void GuiWindowCtrl::onTouchMove(const GuiEvent &event)
 void GuiWindowCtrl::onTouchLeave(const GuiEvent &event)
 {
 	curHitRegion = None;
+	Parent::onTouchLeave(event);
 }
 
 void GuiWindowCtrl::onTouchDown(const GuiEvent &event)

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

@@ -105,6 +105,8 @@ class GuiWindowCtrl : public GuiControl
 	   Region curHitRegion;
 	   bool mPageDocked; //True when docked in a GuiTabPageCtrl. 
 	   void dockToPage();
+	   void undockFromPage();
+	   S32 getTitleHeight() { return mTitleHeight; }
 
 	   Region findHitRegion(const Point2I &);
 	   GuiControlState getRegionCurrentState(GuiWindowCtrl::Region region);