From 309ebb84a8cf93e03e2594525aa128b3002040bf Mon Sep 17 00:00:00 2001
From: Leslie Linden <leslie@lindenlab.com>
Date: Wed, 12 Oct 2011 17:43:47 -0700
Subject: * Floater positioning now based on position of other cascading
 windows currently   open.

---
 indra/llui/llfloater.cpp                           | 84 ++++++++++++++--------
 indra/llui/llfloater.h                             | 19 +++--
 indra/llui/llfloaterreg.cpp                        | 73 +++++++++++++++++--
 indra/llui/llfloaterreg.h                          |  2 +
 indra/newview/llnearbychatbar.cpp                  |  9 ++-
 indra/newview/llnearbychatbar.h                    |  2 +-
 .../skins/default/xui/en/floater_camera.xml        |  4 +-
 .../skins/default/xui/en/floater_chat_bar.xml      |  4 +-
 .../skins/default/xui/en/floater_moveview.xml      |  4 +-
 9 files changed, 152 insertions(+), 49 deletions(-)

diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0398c0d7eb..984b710b9d 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -175,6 +175,8 @@ LLFloater::Params::Params()
 	save_visibility("save_visibility", false),
 	can_dock("can_dock", false),
 	open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE),
+	specified_left("specified_left"),
+	specified_bottom("specified_bottom"),
 	header_height("header_height", 0),
 	legacy_header_height("legacy_header_height", 0),
 	close_image("close_image"),
@@ -242,6 +244,9 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
 	mCanClose(p.can_close),
 	mDragOnLeft(p.can_drag_on_left),
 	mResizable(p.can_resize),
+	mOpenPositioning(p.open_positioning),
+	mSpecifiedLeft(p.specified_left),
+	mSpecifiedBottom(p.specified_bottom),
 	mMinWidth(p.min_width),
 	mMinHeight(p.min_height),
 	mHeaderHeight(p.header_height),
@@ -678,6 +683,7 @@ void LLFloater::openFloater(const LLSD& key)
 	}
 	else
 	{
+		applyControlsAndPosition(LLFloaterReg::getLastFloaterCascading());
 		setMinimized(FALSE);
 		setVisibleAndFrontmost(mAutoFocus);
 	}
@@ -840,39 +846,54 @@ LLMultiFloater* LLFloater::getHost()
 	return (LLMultiFloater*)mHostHandle.get(); 
 }
 
-void LLFloater::applySavedVariables()
+void LLFloater::applyControlsAndPosition(LLFloater* other)
 {
-	applyRectControl();
-	applyDockState();
+	if (!applyDockState())
+	{
+		if (!applyRectControl())
+		{
+			applyPositioning(other);
+		}
+	}
 }
 
-void LLFloater::applyRectControl()
+bool LLFloater::applyRectControl()
 {
+	bool saved_rect = false;
+
 	// If we have a saved rect, use it
 	if (mRectControl.size() > 1)
 	{
 		const LLRect& rect = getControlGroup()->getRect(mRectControl);
-		if (rect.notEmpty())
+		saved_rect = rect.notEmpty();
+		if (saved_rect)
 		{
 			setOrigin(rect.mLeft, rect.mBottom);
+
 			if (mResizable)
 			{
 				reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
 			}
 		}
 	}
+
+	return saved_rect;
 }
 
-void LLFloater::applyDockState()
+bool LLFloater::applyDockState()
 {
+	bool docked = false;
+
 	if (mDocStateControl.size() > 1)
 	{
-		bool dockState = getControlGroup()->getBOOL(mDocStateControl);
-		setDocked(dockState);
+		docked = getControlGroup()->getBOOL(mDocStateControl);
+		setDocked(docked);
 	}
+
+	return docked;
 }
 
-void LLFloater::applyPositioning()
+void LLFloater::applyPositioning(LLFloater* other)
 {
 	// Otherwise position according to the positioning code
 	switch (mOpenPositioning)
@@ -884,28 +905,33 @@ void LLFloater::applyPositioning()
 	case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED:
 		{
 			// Translate relative to snap rect
-			LLRect r = getRect();
-			r.mBottom = getSnapRect().getHeight() - r.getHeight() - r.mBottom;
-			setOrigin(r.mLeft, r.mBottom);
-			translateIntoRect(getSnapRect(), FALSE);
+			setOrigin(mSpecifiedLeft, mSpecifiedBottom);
+			const LLRect& snap_rect = gFloaterView->getSnapRect();
+			translate(snap_rect.mLeft, snap_rect.mBottom);
+			translateIntoRect(snap_rect, FALSE);
 		}
 		break;
 
 	case LLFloaterEnums::OPEN_POSITIONING_CASCADING:
+		if (other != NULL)
 		{
-			static const U32 CASCADING_FLOATER_HOFFSET = 25;
-			static const U32 CASCADING_FLOATER_VOFFSET = 25;
-			static const S32 CASCADING_FLOATER_LIMIT = 15;
-			static S32 cascading_floater_count = 1; 
-			const S32 top = CASCADING_FLOATER_VOFFSET * cascading_floater_count;
-			const S32 left = CASCADING_FLOATER_HOFFSET * cascading_floater_count;
-			setOrigin(left, top);
-			translateIntoRect(getSnapRect(), FALSE);
+			stackWith(*other);
+		}
+		else
+		{
+			static const U32 CASCADING_FLOATER_HOFFSET = 0;
+			static const U32 CASCADING_FLOATER_VOFFSET = 0;
+			
+			const LLRect& snap_rect = gFloaterView->getSnapRect();
 
-			if (++cascading_floater_count > CASCADING_FLOATER_LIMIT)
-			{
-				cascading_floater_count = 1;
-			}
+			const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET;
+			const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET;
+
+			S32 rect_height = getRect().getHeight();
+			setOrigin(horizontal_offset, vertical_offset - rect_height);
+
+			translate(snap_rect.mLeft, snap_rect.mBottom);
+			translateIntoRect(snap_rect, FALSE);
 		}
 		break;
 
@@ -2891,9 +2917,11 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
 	mHeaderHeight = p.header_height;
 	mLegacyHeaderHeight = p.legacy_header_height;
 	mSingleInstance = p.single_instance;
+
 	mOpenPositioning = p.open_positioning;
+	mSpecifiedLeft = p.specified_left;
+	mSpecifiedBottom = p.specified_bottom;
 
-	/*
 	if (p.save_rect && mRectControl.empty())
 	{
 		mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set
@@ -2901,8 +2929,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
 	if (p.save_visibility)
 	{
 		mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
-	}*/
-
+	}
 	if(p.save_dock_state)
 	{
 		mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set
@@ -3053,7 +3080,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
 		llerrs << "Failed to construct floater " << getName() << llendl;
 	}
 
-	applyPositioning();
 	applyRectControl(); // If we have a saved rect control, apply it
 	gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen	
 
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index b404306e94..b094c76168 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -130,6 +130,9 @@ public:
 								can_dock;
 		
 		Optional<LLFloaterEnums::EOpenPositioning>	open_positioning;
+		Optional<S32>								specified_left;
+		Optional<S32>								specified_bottom;
+
 		
 		Optional<S32>			header_height,
 								legacy_header_height; // HACK see initFromXML()
@@ -291,8 +294,6 @@ public:
 
 	virtual void    setTornOff(bool torn_off) { mTornOff = torn_off; }
 
-	void			stackWith(LLFloater& other);
-
 	// Return a closeable floater, if any, given the current focus.
 	static LLFloater* getClosableFloaterFromFocus(); 
 
@@ -317,12 +318,16 @@ public:
 	void			updateTransparency(ETypeTransparency transparency_type);
 		
 	void			enableResizeCtrls(bool enable, bool width = true, bool height = true);
+
+	bool			isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mOpenPositioning); }
 protected:
-	virtual void    applySavedVariables();
+	void			applyControlsAndPosition(LLFloater* other);
+
+	void			stackWith(LLFloater& other);
 
-	virtual void	applyRectControl();
-	void			applyDockState();
-	void			applyPositioning();
+	virtual bool	applyRectControl();
+	bool			applyDockState();
+	void			applyPositioning(LLFloater* other);
 	void			storeRectControl();
 	void			storeVisibilityControl();
 	void			storeDockStateControl();
@@ -412,6 +417,8 @@ private:
 	BOOL			mResizable;
 
 	LLFloaterEnums::EOpenPositioning	mOpenPositioning;
+	S32									mSpecifiedLeft;
+	S32									mSpecifiedBottom;
 	
 	S32				mMinWidth;
 	S32				mMinHeight;
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 058223abbd..a148f5a32e 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -59,19 +59,57 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con
 //static
 LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
 {
-	LLRect rect;
 	const std::string& groupname = sGroupMap[name];
 	if (!groupname.empty())
 	{
 		instance_list_t& list = sInstanceMap[groupname];
 		if (!list.empty())
 		{
-			return list.back();
+			for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter)
+			{
+				LLFloater* inst = *iter;
+
+				if (inst->getVisible() && !inst->isMinimized())
+				{
+					return inst;
+				}
+			}
 		}
 	}
 	return NULL;
 }
 
+LLFloater* LLFloaterReg::getLastFloaterCascading()
+{
+	LLRect candidate_rect;
+	candidate_rect.mTop = 100000;
+	LLFloater* candidate_floater = NULL;
+
+	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
+	for( ; it != it_end; ++it)
+	{
+		const std::string& group_name = it->second;
+
+		instance_list_t& instances = sInstanceMap[group_name];
+
+		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+		{
+			LLFloater* inst = *iter;
+
+			if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING))
+			{
+				if (candidate_rect.mTop > inst->getRect().mTop)
+				{
+					candidate_floater = inst;
+					candidate_rect = inst->getRect();
+				}
+			}
+		}
+	}
+
+	return candidate_floater;
+}
+
 //static
 LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)
 {
@@ -127,9 +165,10 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
 					res->mKey = key;
 				}
 				res->setInstanceName(name);
-				res->applySavedVariables(); // Can't apply rect and dock state until setting instance name
 
-				// apply list.size() and possibly stackWith(getLastFloaterInGroup(groupname))
+				LLFloater *last_floater = (list.empty() ? NULL : list.back());
+				res->applyControlsAndPosition(last_floater);
+
 				gFloaterView->adjustToFitScreen(res, false);
 
 				list.push_back(res);
@@ -533,3 +572,29 @@ bool LLFloaterReg::floaterInstanceMinimized(const LLSD& sdname)
 	LLFloater* instance = findInstance(name, key); 
 	return LLFloater::isShown(instance);
 }
+
+// static
+U32 LLFloaterReg::getVisibleFloaterInstanceCount()
+{
+	U32 count = 0;
+
+	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
+	for( ; it != it_end; ++it)
+	{
+		const std::string& group_name = it->second;
+
+		instance_list_t& instances = sInstanceMap[group_name];
+
+		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+		{
+			LLFloater* inst = *iter;
+
+			if (inst->getVisible() && !inst->isMinimized())
+			{
+				count++;
+			}
+		}
+	}
+
+	return count;
+}
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 07ae45cc4c..817fe2e8c6 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -87,6 +87,7 @@ public:
 
 	// Helpers
 	static LLFloater* getLastFloaterInGroup(const std::string& name);
+	static LLFloater* getLastFloaterCascading();
 	
 	// Find / get (create) / remove / destroy
 	static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD());
@@ -153,6 +154,7 @@ public:
 
 	static void blockShowFloaters(bool value) { sBlockShowFloaters = value;}
 	
+	static U32 getVisibleFloaterInstanceCount();
 };
 
 #endif
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index cd84275ef0..3e4228cfb6 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -109,15 +109,18 @@ BOOL LLNearbyChatBar::postBuild()
 	return TRUE;
 }
 
-void LLNearbyChatBar::applyRectControl()
+bool LLNearbyChatBar::applyRectControl()
 {
-	LLFloater::applyRectControl();
-	if (getRect().getHeight() >  getMinHeight())
+	bool rect_controlled = LLFloater::applyRectControl();
+	
+	if (getRect().getHeight() > getMinHeight())
 	{
 		getChildView("nearby_chat")->setVisible(true);
 		mExpandedHeight = getRect().getHeight();
 		enableResizeCtrls(true);
 	}
+
+	return rect_controlled;
 }
 
 void LLNearbyChatBar::onChatFontChange(LLFontGL* fontp)
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index 5a7edac1bb..bc00c1b9fc 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -71,7 +71,7 @@ protected:
 	void onChatBoxCommit();
 	void onChatFontChange(LLFontGL* fontp);
 
-	/* virtual */ void applyRectControl();
+	/* virtual */ bool applyRectControl();
 
 	void onToggleNearbyChatPanel();
 
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index 7f3abbb481..20d0fa1c91 100644
--- a/indra/newview/skins/default/xui/en/floater_camera.xml
+++ b/indra/newview/skins/default/xui/en/floater_camera.xml
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  open_positioning="specified"
+ specified_left="683"
+ specified_bottom="0"
  legacy_header_height="18"
  can_minimize="true"
  can_close="true"
  follows="bottom"
  height="164"
  layout="topleft"
- left="683"
- bottom="0"
  name="camera_floater"
  help_topic="camera_floater"
  save_visibility="true"
diff --git a/indra/newview/skins/default/xui/en/floater_chat_bar.xml b/indra/newview/skins/default/xui/en/floater_chat_bar.xml
index 924e4bc11e..9229741801 100644
--- a/indra/newview/skins/default/xui/en/floater_chat_bar.xml
+++ b/indra/newview/skins/default/xui/en/floater_chat_bar.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  open_positioning="specified"
+ specified_left="150"
+ specified_bottom="0"
  height="60"
- left="150"
- bottom="0"
  layout="topleft"
  legacy_header_height="25"
  single_instance="true"
diff --git a/indra/newview/skins/default/xui/en/floater_moveview.xml b/indra/newview/skins/default/xui/en/floater_moveview.xml
index 3d23a94ec2..cbbd68beb3 100644
--- a/indra/newview/skins/default/xui/en/floater_moveview.xml
+++ b/indra/newview/skins/default/xui/en/floater_moveview.xml
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
  open_positioning="specified"
+ specified_left="535"
+ specified_bottom="0"
  legacy_header_height="18"
  can_dock="false"
  can_minimize="true"
  can_close="true"
  follows="bottom"
  height="110"
- left="535"
- bottom="0"
  layout="topleft"
  name="move_floater"
  help_topic="move_floater"
-- 
cgit v1.2.3