diff --git a/etc/message.xml b/etc/message.xml
index 4534be6db8e18f689c9b744213e92b373d524adf..ddbfa58ddbdff7074f69cb30971c322c309ffb23 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -284,6 +284,14 @@
 					<boolean>true</boolean>
 				</map>
 
+				<key>AgentDropGroup</key>
+				<map>
+				    <key>flavor</key>
+				    <string>llsd</string>
+				    <key>trusted-sender</key>
+				    <boolean>true</boolean>
+				</map>
+
 				<key>ChatterBoxSessionStartReply</key>
 				<map>
 					<key>flavor</key>
@@ -315,7 +323,15 @@
 					<key>trusted-sender</key>
 					<boolean>true</boolean>
 				</map>
-
+				
+				<key>ChatterBoxSessionUpdate</key>
+				<map>
+					<key>flavor</key>
+					<string>llsd</string>
+					<key>trusted-sender</key>
+					<boolean>true</boolean>
+				</map>
+				
 				<key>ChatterBoxInvitation</key>
 				<map>
 					<key>flavor</key>
diff --git a/indra/llcharacter/llhandmotion.h b/indra/llcharacter/llhandmotion.h
index 39c61b2154afd31fe02a9d6d7c731f30f859f4db..662800784bd898787f7294cf63188b14e85aa114 100644
--- a/indra/llcharacter/llhandmotion.h
+++ b/indra/llcharacter/llhandmotion.h
@@ -124,6 +124,8 @@ class LLHandMotion :
 	// called when a motion is deactivated
 	virtual void onDeactivate();
 
+	virtual BOOL canDeprecate() { return FALSE; }
+
 	static LLString getHandPoseName(eHandPose pose);
 	static eHandPose getHandPose(LLString posename);
 
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index cd8c79a84d9ee11421f33c96fe13c497bf5363bf..96b2ab169b8b9fcd06efc25cd73465d9edbcfea9 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -183,7 +183,15 @@ template <class LLDATATYPE>
 inline LLDATATYPE llmax(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATATYPE& d3)
 {
 	LLDATATYPE r = llmax(d1,d2);
-	return (r > d3 ? r : d3);
+	return llmax(r, d3);
+}
+
+template <class LLDATATYPE> 
+inline LLDATATYPE llmax(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATATYPE& d3, const LLDATATYPE& d4)
+{
+	LLDATATYPE r1 = llmax(d1,d2);
+	LLDATATYPE r2 = llmax(d3,d4);
+	return llmax(r1, r2);
 }
 
 template <class LLDATATYPE> 
@@ -199,6 +207,14 @@ inline LLDATATYPE llmin(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATA
 	return (r < d3 ? r : d3);
 }
 
+template <class LLDATATYPE> 
+inline LLDATATYPE llmin(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATATYPE& d3, const LLDATATYPE& d4)
+{
+	LLDATATYPE r1 = llmin(d1,d2);
+	LLDATATYPE r2 = llmin(d3,d4);
+	return llmin(r1, r2);
+}
+
 template <class LLDATATYPE> 
 inline LLDATATYPE llclamp(const LLDATATYPE& a, const LLDATATYPE& minval, const LLDATATYPE& maxval)
 {
diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h
index 3018cc671b9950221e082986f742f24b98c1c5bf..8ba883a0eeb0ab72bd494361c1d2a4a9dbf67915 100644
--- a/indra/llcommon/llevent.h
+++ b/indra/llcommon/llevent.h
@@ -179,7 +179,7 @@ class LLObservable
 		if (mDispatcher.notNull()) mDispatcher->removeListener(listener);
 	}
 	// Notifies the dispatcher of an event being fired.
-	void fireEvent(LLPointer<LLEvent> event, LLSD filter);
+	void fireEvent(LLPointer<LLEvent> event, LLSD filter = LLSD());
 
 protected:
 	LLPointer<LLEventDispatcher> mDispatcher;
diff --git a/indra/llcommon/llmortician.cpp b/indra/llcommon/llmortician.cpp
index cab3a7f973019595b78a9c2455e4e1c6dfd64c4e..b3e25104cb006eddf86e35b274f4fc746806b0a4 100644
--- a/indra/llcommon/llmortician.cpp
+++ b/indra/llcommon/llmortician.cpp
@@ -33,20 +33,20 @@
 
 #include <list>
 
-std::list<LLMortician*> gGraveyard;
+std::list<LLMortician*> LLMortician::sGraveyard;
 
 BOOL LLMortician::sDestroyImmediate = FALSE;
 
 LLMortician::~LLMortician() 
 {
-	gGraveyard.remove(this);
+	sGraveyard.remove(this);
 }
 
 void LLMortician::updateClass() 
 {
-	while (!gGraveyard.empty()) 
+	while (!sGraveyard.empty()) 
 	{
-		LLMortician* dead = gGraveyard.front();
+		LLMortician* dead = sGraveyard.front();
 		delete dead;
 	}
 }
@@ -56,7 +56,7 @@ void LLMortician::die()
 	// It is valid to call die() more than once on something that hasn't died yet
 	if (sDestroyImmediate)
 	{
-		// *NOTE: This is a hack to ensure destruction order on shutdown.
+		// *NOTE: This is a hack to ensure destruction order on shutdown (relative to non-mortician controlled classes).
 		mIsDead = TRUE;
 		delete this;
 		return;
@@ -64,7 +64,7 @@ void LLMortician::die()
 	else if (!mIsDead)
 	{
 		mIsDead = TRUE;
-		gGraveyard.push_back(this);
+		sGraveyard.push_back(this);
 	}
 }
 
diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h
index 24a38520e9cbde5f4733cf567e42185ad92361e5..606ac0dc39da7fe05b2263755eda968c8165f8c1 100644
--- a/indra/llcommon/llmortician.h
+++ b/indra/llcommon/llmortician.h
@@ -50,6 +50,8 @@ class LLMortician
 	static BOOL sDestroyImmediate;
 
 	BOOL mIsDead;
+
+	static std::list<LLMortician*> sGraveyard;
 };
 
 #endif
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index a0f337c2de9260c1cda526646eeedbf33befd457..992c883a7e32274ef5f989307f4aee083a68b221 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -301,3 +301,123 @@ char* ll_pretty_print_sd(const LLSD& sd)
 	buffer[bufferSize - 1] = '\0';
 	return buffer;
 }
+
+//compares the structure of an LLSD to a template LLSD and stores the
+//"valid" values in a 3rd LLSD.  Default values are stored in the template
+//
+//If the llsd to test has a specific key to a map and the values
+//are not of the same type, false is returned or if the LLSDs are not
+//of the same value.  Ordering of arrays matters
+//Otherwise, returns true
+BOOL compare_llsd_with_template(
+	const LLSD& llsd_to_test,
+	const LLSD& template_llsd,
+	LLSD& resultant_llsd)
+{
+	if (
+		llsd_to_test.isUndefined() &&
+		template_llsd.isDefined() )
+	{
+		resultant_llsd = template_llsd;
+		return TRUE;
+	}
+	else if ( llsd_to_test.type() != template_llsd.type() )
+	{
+		resultant_llsd = LLSD();
+		return FALSE;
+	}
+
+	if ( llsd_to_test.isArray() )
+	{
+		//they are both arrays
+		//we loop over all the items in the template
+		//verifying that the to_test has a subset (in the same order)
+		//any shortcoming in the testing_llsd are just taken
+		//to be the rest of the template
+		LLSD data;
+		LLSD::array_const_iterator test_iter;
+		LLSD::array_const_iterator template_iter;
+
+		resultant_llsd = LLSD::emptyArray();
+		test_iter = llsd_to_test.beginArray();
+
+		for (
+			template_iter = template_llsd.beginArray();
+			(template_iter != template_llsd.endArray() &&
+			 test_iter != llsd_to_test.endArray());
+			++template_iter)
+		{
+			if ( !compare_llsd_with_template(
+					 *test_iter,
+					 *template_iter,
+					 data) )
+			{
+				resultant_llsd = LLSD();
+				return FALSE;
+			}
+			else
+			{
+				resultant_llsd.append(data);
+			}
+
+			++test_iter;
+		}
+
+		//so either the test or the template ended
+		//we do another loop now to the end of the template
+		//grabbing the default values
+		for (;
+			 template_iter != template_llsd.endArray();
+			 ++template_iter)
+		{
+			resultant_llsd.append(*template_iter);
+		}
+	}
+	else if ( llsd_to_test.isMap() )
+	{
+		//now we loop over the keys of the two maps
+		//any excess is taken from the template
+		//excess is ignored in the test
+		LLSD value;
+		LLSD::map_const_iterator template_iter;
+
+		resultant_llsd = LLSD::emptyMap();
+		for (
+			template_iter = template_llsd.beginMap();
+			template_iter != template_llsd.endMap();
+			++template_iter)
+		{
+			if ( llsd_to_test.has(template_iter->first) )
+			{
+				//the test LLSD has the same key
+				if ( !compare_llsd_with_template(
+						 llsd_to_test[template_iter->first],
+						 template_iter->second,
+						 value) )
+				{
+					resultant_llsd = LLSD();
+					return FALSE;
+				}
+				else
+				{
+					resultant_llsd[template_iter->first] = value;
+				}
+			}
+			else
+			{
+				//test llsd doesn't have it...take the
+				//template as default value
+				resultant_llsd[template_iter->first] =
+					template_iter->second;
+			}
+		}
+	}
+	else
+	{
+		//of same type...take the test llsd's value
+		resultant_llsd = llsd_to_test;
+	}
+
+
+	return TRUE;
+}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 699d5093e1f8f9893656f858b78d3b10f24231fb..17a881d9cbe042b758695e0921e827bffb649229 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -91,4 +91,14 @@ char* ll_print_sd(const LLSD& sd);
 // Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
 char* ll_pretty_print_sd(const LLSD& sd);
 
+//compares the structure of an LLSD to a template LLSD and stores the
+//"valid" values in a 3rd LLSD. Default values
+//are pulled from the template.  Ordering of arrays matters
+//Returns false if the test is of same type but values differ in type
+//Otherwise, returns true
+BOOL compare_llsd_with_template(
+	const LLSD& llsd_to_test,
+	const LLSD& template_llsd,
+	LLSD& resultant_llsd);
+
 #endif // LL_LLSDUTIL_H
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index ec4ff335c993bb6169b45491939b377fb3636847..d4925d8bee2e988eecbbf501cc25aa5c076abde5 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -299,6 +299,10 @@ class LLStringBase : public std::basic_string<T>
 	// a.k.a. strdictcmp()
 	static S32		compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
 
+	// Case *in*sensitive comparison with good handling of numbers.  Does not use current locale.
+	// a.k.a. strdictcmp()
+	static S32		compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
+
 	// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
 	static BOOL		precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
 
@@ -310,7 +314,7 @@ class LLStringBase : public std::basic_string<T>
 	// Copies src into dst at a given offset.  
 	static void		copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
 	
-#ifdef _DEBUG
+#ifdef _DEBUG	
 	static void		testHarness();
 #endif
 
@@ -678,6 +682,39 @@ S32 LLStringBase<T>::compareDict(const std::basic_string<T>& astr, const std::ba
 	return ca-cb;
 }
 
+template<class T>
+S32 LLStringBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+{
+	const T* a = astr.c_str();
+	const T* b = bstr.c_str();
+	T ca, cb;
+	S32 ai, bi, cnt = 0;
+
+	ca = *(a++);
+	cb = *(b++);
+	while( ca && cb ){
+		if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
+		if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
+		if( LLStringOps::isDigit(ca) ){
+			if( cnt-->0 ){
+				if( cb!=ca ) break;
+			}else{
+				if( !LLStringOps::isDigit(cb) ) break;
+				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
+				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
+				if( ai<bi ){ ca=0; break; }
+				if( bi<ai ){ cb=0; break; }
+				if( ca!=cb ) break;
+				cnt = ai;
+			}
+		}else if( ca!=cb ){   break;
+		}
+		ca = *(a++);
+		cb = *(b++);
+	}
+	return ca-cb;
+}
+
 // Puts compareDict() in a form appropriate for LL container classes to use for sorting.
 // static 
 template<class T> 
diff --git a/indra/llcommon/roles_constants.h b/indra/llcommon/roles_constants.h
index 1a7c977f21c7a76672ce9ab942fc5fa97d64937b..12bd21ec205b878c8fde9884caaead8d13aae250 100644
--- a/indra/llcommon/roles_constants.h
+++ b/indra/llcommon/roles_constants.h
@@ -56,12 +56,12 @@ enum LLRoleChangeType
 // Powers
 //
 
-// KNOWN HOLES:
-// bit 0x1 << 37 (GP_OBJECT_RETURN)
+// KNOWN HOLES: use these for any single bit powers you need
+// bit 0x1 << 41
+// bit 0x1 << 46
+// bit 0x1 << 49 and above
 
 // These powers were removed to make group roles simpler
-// bit 0x1 << 27 (GP_LAND_ALLOW_SCRIPTS) 
-// bit 0x1 << 16 (GP_LAND_VIEW_OWNED)
 // bit 0x1 << 41 (GP_ACCOUNTING_VIEW)
 // bit 0x1 << 46 (GP_PROPOSAL_VIEW)
 
@@ -116,18 +116,19 @@ const U64 GP_LAND_MANAGE_PASSES	= 0x1LL << 31;	// Change Sell Pass Settings
 const U64 GP_LAND_ADMIN			= 0x1LL << 32;	// Eject and Freeze Users on the land
 
 // Parcel Content
-const U64 GP_LAND_RETURN_GROUP_OWNED= 0x1LL << 48;	// Return objects on parcel that are owned by the group
 const U64 GP_LAND_RETURN_GROUP_SET	= 0x1LL << 33;	// Return objects on parcel that are set to group
 const U64 GP_LAND_RETURN_NON_GROUP	= 0x1LL << 34;	// Return objects on parcel that are not set to group
+const U64 GP_LAND_RETURN_GROUP_OWNED= 0x1LL << 48;	// Return objects on parcel that are owned by the group
+
 // Select a power-bit based on an object's relationship to a parcel.
 const U64 GP_LAND_RETURN		= GP_LAND_RETURN_GROUP_OWNED 
 								| GP_LAND_RETURN_GROUP_SET	
 								| GP_LAND_RETURN_NON_GROUP;
+
 const U64 GP_LAND_GARDENING		= 0x1LL << 35;	// Parcel Gardening - plant and move linden trees
 
 // Object Management
 const U64 GP_OBJECT_DEED			= 0x1LL << 36;	// Deed Object
-// HOLE -- 0x1LL << 37
 const U64 GP_OBJECT_MANIPULATE		= 0x1LL << 38;	// Manipulate Group Owned Objects (Move, Copy, Mod)
 const U64 GP_OBJECT_SET_SALE		= 0x1LL << 39;	// Set Group Owned Object for Sale
 
@@ -142,9 +143,10 @@ const U64 GP_NOTICES_RECEIVE		= 0x1LL << 43;	// Receive Notices and View Notice
 const U64 GP_PROPOSAL_START		= 0x1LL << 44;	// Start Proposal
 const U64 GP_PROPOSAL_VOTE		= 0x1LL << 45;	// Vote on Proposal
 
-const U64 GP_SESSION_JOIN = 0x1LL << 46; //can join session
-const U64 GP_SESSION_VOICE = 0x1LL << 47; //can hear/talk
-const U64 GP_SESSION_MODERATOR = 0x1LL << 49; //can mute people's session
+// Group chat moderation related
+const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session
+const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk
+const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session
 
 const U64 GP_DEFAULT_MEMBER = GP_ACCOUNTING_ACCOUNTABLE
 								| GP_LAND_ALLOW_SET_HOME
diff --git a/indra/llinventory/lluserrelations.cpp b/indra/llinventory/lluserrelations.cpp
index 0f1b48ecd15f4e81d056bdb507fff4dc9f07bd10..e96cb1e1c11c1edeba5ec5379b6e3bbd2eea13f5 100644
--- a/indra/llinventory/lluserrelations.cpp
+++ b/indra/llinventory/lluserrelations.cpp
@@ -41,6 +41,7 @@ const LLRelationship LLRelationship::DEFAULT_RELATIONSHIP = LLRelationship(GRANT
 LLRelationship::LLRelationship() :
 	mGrantToAgent(0),
 	mGrantFromAgent(0),
+	mChangeSerialNum(0),
 	mIsOnline(false)
 {
 }
@@ -48,6 +49,7 @@ LLRelationship::LLRelationship() :
 LLRelationship::LLRelationship(S32 grant_to, S32 grant_from, bool is_online) :
 	mGrantToAgent(grant_to),
 	mGrantFromAgent(grant_from),
+	mChangeSerialNum(0),
 	mIsOnline(is_online)
 {
 }
@@ -60,6 +62,7 @@ bool LLRelationship::isOnline() const
 void LLRelationship::online(bool is_online)
 {
 	mIsOnline = is_online;
+	mChangeSerialNum++;
 }
 
 bool LLRelationship::isRightGrantedTo(S32 rights) const
@@ -86,12 +89,14 @@ void LLRelationship::grantRights(S32 to_agent, S32 from_agent)
 {
 	mGrantToAgent |= to_agent;
 	mGrantFromAgent |= from_agent;
+	mChangeSerialNum++;
 }
 
 void LLRelationship::revokeRights(S32 to_agent, S32 from_agent)
 {
 	mGrantToAgent &= ~to_agent;
 	mGrantFromAgent &= ~from_agent;
+	mChangeSerialNum++;
 }
 
 
diff --git a/indra/llinventory/lluserrelations.h b/indra/llinventory/lluserrelations.h
index 448301383e43407d89fd21873671e2788f36c3d7..36472215f6817d60032a7362883938e20baca075 100644
--- a/indra/llinventory/lluserrelations.h
+++ b/indra/llinventory/lluserrelations.h
@@ -142,8 +142,18 @@ class LLRelationship
 	 */
 	S32 getRightsGrantedFrom() const;
 
-	void setRightsTo(S32 to_agent) { mGrantToAgent = to_agent; }
-	void setRightsFrom(S32 from_agent) { mGrantFromAgent = from_agent; }
+	void setRightsTo(S32 to_agent) { mGrantToAgent = to_agent; mChangeSerialNum++; }
+	void setRightsFrom(S32 from_agent) { mGrantFromAgent = from_agent; mChangeSerialNum++;}
+
+	/**
+	 * @brief Get the change count for this agent
+	 *
+	 * Every change to rights will increment the serial number
+	 * allowing listeners to determine when a relationship value is actually new
+	 *
+	 * @return change serial number for relationship
+	 */
+	S32 getChangeSerialNum() const { return mChangeSerialNum; }
 
 	/**
 	 * @brief Grant a set of rights.
@@ -171,6 +181,7 @@ class LLRelationship
 protected:
 	S32 mGrantToAgent;
 	S32 mGrantFromAgent;
+	S32 mChangeSerialNum;
 	bool mIsOnline;
 };
 
diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h
index 00a1b03335938d7ac4bcd961aa261846bd4af641..e7b15dcc589fd04d8bfab620c1826382273ebd06 100644
--- a/indra/llmath/llrect.h
+++ b/indra/llmath/llrect.h
@@ -215,7 +215,12 @@ template <class Type> class LLRectBase
 		mLeft = llmin(mLeft, mRight);
 		mBottom = llmin(mBottom, mTop);
 	}
-	
+
+	bool isNull() const
+	{
+		return mLeft == mRight || mBottom == mTop;
+	}
+
 	void unionWith(const LLRectBase &other)
 	{
 		mLeft = llmin(mLeft, other.mLeft);
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index b80fa069c7b7057e94422b541ce369344303a5ce..d09af7a8c4773c78e5af24f6ec190b55a9a6fd82 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -163,6 +163,7 @@ inline LLColor3::LLColor3(F32 r, F32 g, F32 b)
 	mV[VZ] = b;
 }
 
+
 inline LLColor3::LLColor3(const F32 *vec)
 {
 	mV[VX] = vec[VX];
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index 1e6232fc9d27a678060c84b2fb3035a0bd33e966..0514870ef667d88e429fdcfd39d927bc3b10115f 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -260,6 +260,7 @@ inline LLColor4::LLColor4(U32 clr)
 	mV[VW] = (clr>>24) * (1.0f/255.0f);
 }
 
+
 inline LLColor4::LLColor4(const F32 *vec)
 {
 	mV[VX] = vec[VX];
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index 473eaea76de7869065201edc6cd82a06049c6317..85a1e229abac18166e595e472df5672422356407 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -723,7 +723,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 		const LLHTTPNode* node = mRootNode.traverse(mPath, context);
 		if(node)
 		{
- 			llinfos << "LLHTTPResponder::process_impl found node for "
+ 			lldebugs << "LLHTTPResponder::process_impl found node for "
 				<< mAbsPathAndQuery << llendl;
 
   			// Copy everything after mLast read to the out.
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index a1b63ead75bf90e7a7dbf4a9fd1eba4ed0172e6b..aca7a60bf17fa244ba4986ba8813b43fb7a1552f 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -705,21 +705,28 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count )
 			// But we don't want to acknowledge UseCircuitCode until the circuit is
 			// available, which is why the acknowledgement test is done above.  JC
 
-			valid_packet = mTemplateMessageReader->validateMessage(buffer, 
-														   receive_size,
-														   host);
+			valid_packet = mTemplateMessageReader->validateMessage(
+				buffer,
+				receive_size,
+				host);
 
 			// UseCircuitCode is allowed in even from an invalid circuit, so that
 			// we can toss circuits around.
-			if(valid_packet && !cdp && 
-			   (mTemplateMessageReader->getMessageName() != _PREHASH_UseCircuitCode))
+			if(
+				valid_packet &&
+				!cdp && 
+				(mTemplateMessageReader->getMessageName() !=
+				 _PREHASH_UseCircuitCode))
 			{
 				logMsgFromInvalidCircuit( host, recv_reliable );
 				clearReceiveState();
 				valid_packet = FALSE;
 			}
 
-			if(valid_packet && cdp && !cdp->getTrusted() && 
+			if(
+				valid_packet &&
+				cdp &&
+				!cdp->getTrusted() && 
 				mTemplateMessageReader->isTrusted())
 			{
 				logTrustedMsgFromUntrustedCircuit( host );
@@ -729,8 +736,9 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count )
 				valid_packet = FALSE;
 			}
 
-			if (valid_packet
-			&& mTemplateMessageReader->isBanned(cdp && cdp->getTrusted()))
+			if (
+				valid_packet &&
+				mTemplateMessageReader->isBanned(cdp && cdp->getTrusted()))
 			{
 				llwarns << "LLMessageSystem::checkMessages "
 					<< "received banned message "
@@ -1159,9 +1167,10 @@ LLHTTPClient::ResponderPtr LLMessageSystem::createResponder(const std::string& n
 {
 	if(mSendReliable)
 	{
-		return new LLFnPtrResponder(mReliablePacketParams.mCallback,
-									mReliablePacketParams.mCallbackData,
-									name);
+		return new LLFnPtrResponder(
+			mReliablePacketParams.mCallback,
+			mReliablePacketParams.mCallbackData,
+			name);
 	}
 	else
 	{
@@ -1170,8 +1179,10 @@ LLHTTPClient::ResponderPtr LLMessageSystem::createResponder(const std::string& n
 //		llwarns << "LLMessageSystem::sendMessage: Sending unreliable "
 //				<< mMessageBuilder->getMessageName() << " message via HTTP"
 //				<< llendl;
-		return new LLFnPtrResponder(NULL, NULL,
-									mMessageBuilder->getMessageName());
+		return new LLFnPtrResponder(
+			NULL,
+			NULL,
+			mMessageBuilder->getMessageName());
 	}
 }
 
@@ -1241,8 +1252,11 @@ S32 LLMessageSystem::sendMessage(const LLHost &host)
 		LLSD message = mLLSDMessageBuilder->getMessage();
 		
 		const LLHTTPSender& sender = LLHTTPSender::getSender(host);
-		sender.send(host, mLLSDMessageBuilder->getMessageName(),
-					message, createResponder(mLLSDMessageBuilder->getMessageName()));
+		sender.send(
+			host,
+			mLLSDMessageBuilder->getMessageName(),
+			message,
+			createResponder(mLLSDMessageBuilder->getMessageName()));
 
 		mSendReliable = FALSE;
 		mReliablePacketParams.clear();
@@ -1423,8 +1437,10 @@ void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_re
 	}
 }
 
-S32 LLMessageSystem::sendMessage(const LLHost &host, const char* name,
-								  const LLSD& message)
+S32 LLMessageSystem::sendMessage(
+	const LLHost &host,
+	const char* name,
+	const LLSD& message)
 {
 	if (!(host.isOk()))
 	{
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 491fbb586ad7624462f9c995fd62221353332e1d..cbfa3c2202871cf7e1f5bf8b9ecb52f61ca6930b 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -196,14 +196,4 @@ class LLImageGL : public LLRefCount
 #endif
 };
 
-//RN: maybe this needs to moved elsewhere?
-class LLImageProviderInterface
-{
-public:
-	LLImageProviderInterface() {};
-	virtual ~LLImageProviderInterface() {};
-
-	virtual LLImageGL* getUIImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
-};
-
 #endif // LL_LLIMAGEGL_H
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 26ce473e082610e7dfee68975f01a66f8ab7fb59..ce3a4b64c7e86a8fa21aa4e81f9e3975483c2a4b 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -59,9 +59,6 @@ S32 BTN_HEIGHT		= 0;
 S32 BTN_GRID		= 12;
 S32 BORDER_SIZE = 1;
 
-// static
-LLFrameTimer	LLButton::sFlashingTimer;
-
 LLButton::LLButton(	const LLString& name, const LLRect& rect, const LLString& control_name, void (*click_callback)(void*), void *callback_data)
 :	LLUICtrl(name, rect, TRUE, NULL, NULL),
 	mClickedCallback( click_callback ),
@@ -79,6 +76,7 @@ LLButton::LLButton(	const LLString& name, const LLRect& rect, const LLString& co
 	mImageDisabled( NULL ),
 	mImageDisabledSelected( NULL ),
 	mToggleState( FALSE ),
+	mIsToggle( FALSE ),
 	mScaleImage( TRUE ),
 	mDropShadowedText( TRUE ),
 	mBorderEnabled( FALSE ),
@@ -86,8 +84,6 @@ LLButton::LLButton(	const LLString& name, const LLRect& rect, const LLString& co
 	mHAlign( LLFontGL::HCENTER ),
 	mLeftHPad( LLBUTTON_H_PAD ),
 	mRightHPad( LLBUTTON_H_PAD ),
-	mFixedWidth( 16 ),
-	mFixedHeight( 16 ),
 	mHoverGlowStrength(0.15f),
 	mCurGlowStrength(0.f),
 	mNeedsHighlight(FALSE),
@@ -134,6 +130,7 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
 	mImageDisabled( NULL ),
 	mImageDisabledSelected( NULL ),
 	mToggleState( FALSE ),
+	mIsToggle( FALSE ),
 	mScaleImage( TRUE ),
 	mDropShadowedText( TRUE ),
 	mBorderEnabled( FALSE ),
@@ -141,8 +138,6 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
 	mHAlign( LLFontGL::HCENTER ),
 	mLeftHPad( LLBUTTON_H_PAD ), 
 	mRightHPad( LLBUTTON_H_PAD ),
-	mFixedWidth( 16 ),
-	mFixedHeight( 16 ),
 	mHoverGlowStrength(0.25f),
 	mCurGlowStrength(0.f),
 	mNeedsHighlight(FALSE),
@@ -158,15 +153,11 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
 
 	if( unselected_image_name != "" )
 	{
+		// user-specified image - don't use fixed borders unless requested
 		setImageUnselected(unselected_image_name);
 		setImageDisabled(unselected_image_name);
 		
 		mDisabledImageColor.mV[VALPHA] = 0.5f;
-		mImageDisabled = mImageUnselected;
-		mDisabledImageColor.mV[VALPHA] = 0.5f;
-		// user-specified image - don't use fixed borders unless requested
-		mFixedWidth = 0;
-		mFixedHeight = 0;
 		mScaleImage = FALSE;
 	}
 	else
@@ -177,13 +168,11 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
 
 	if( selected_image_name != "" )
 	{
+		// user-specified image - don't use fixed borders unless requested
 		setImageSelected(selected_image_name);
 		setImageDisabledSelected(selected_image_name);
 
 		mDisabledImageColor.mV[VALPHA] = 0.5f;
-		// user-specified image - don't use fixed borders unless requested
-		mFixedWidth = 0;
-		mFixedHeight = 0;
 		mScaleImage = FALSE;
 	}
 	else
@@ -273,6 +262,12 @@ void LLButton::onCommit()
 		make_ui_sound("UISndClickRelease");
 	}
 
+	if (mIsToggle)
+	{
+		toggleState();
+	}
+
+	// do this last, as it can result in destroying this button
 	if (mClickedCallback)
 	{
 		(*mClickedCallback)( mCallbackUserData );
@@ -286,6 +281,11 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
 	BOOL handled = FALSE;
 	if( getVisible() && mEnabled && !called_from_parent && ' ' == uni_char && !gKeyboard->getKeyRepeated(' '))
 	{
+		if (mIsToggle)
+		{
+			toggleState();
+		}
+
 		if (mClickedCallback)
 		{
 			(*mClickedCallback)( mCallbackUserData );
@@ -302,11 +302,17 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent )
 	{
 		if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
 		{
+			if (mIsToggle)
+			{
+				toggleState();
+			}
+
+			handled = TRUE;
+
 			if (mClickedCallback)
 			{
 				(*mClickedCallback)( mCallbackUserData );
 			}
-			handled = TRUE;
 		}
 	}
 	return handled;
@@ -354,6 +360,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 			(*mMouseUpCallback)(mCallbackUserData);
 		}
 
+		mMouseDownTimer.stop();
+		mMouseDownTimer.reset();
+
 		// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
 		// If mouseup in the widget, it's been clicked
 		if (pointInView(x, y))
@@ -363,6 +372,11 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 				make_ui_sound("UISndClickRelease");
 			}
 
+			if (mIsToggle)
+			{
+				toggleState();
+			}
+
 			if (mClickedCallback)
 			{
 				(*mClickedCallback)( mCallbackUserData );
@@ -422,8 +436,10 @@ void LLButton::draw()
 		BOOL flash = FALSE;
 		if( mFlashing )
 		{
-			F32 elapsed = LLButton::sFlashingTimer.getElapsedTimeF32();
-			flash = S32(elapsed * 2) & 1;
+			F32 elapsed = mFlashingTimer.getElapsedTimeF32();
+			S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f);
+			// flash on or off?
+			flash = (flash_count % 2 == 0) || flash_count > (F32)LLUI::sConfigGroup->getS32("ButtonFlashCount");
 		}
 
 		BOOL pressed_by_keyboard = FALSE;
@@ -443,24 +459,14 @@ void LLButton::draw()
 		cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
 		screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
 
-		BOOL pressed = pressed_by_keyboard || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
-
-		BOOL display_state = FALSE;
-		if( pressed )
-		{
-			mImagep = mImageSelected;
-			// show the resulting state after releasing the mouse button while it is down
-			display_state = mToggleState ? FALSE : TRUE;
-		}
-		else
-		{
-			display_state = mToggleState || flash;
-		}
+		BOOL pressed = pressed_by_keyboard 
+						|| (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) 
+						|| mToggleState;
 		
 		BOOL use_glow_effect = FALSE;
-		if ( mNeedsHighlight )
+		if ( mNeedsHighlight || flash )
 		{
-			if (display_state)
+			if (pressed)
 			{
 				if (mImageHoverSelected)
 				{
@@ -485,7 +491,7 @@ void LLButton::draw()
 				}
 			}
 		}
-		else if ( display_state )
+		else if ( pressed )
 		{
 			mImagep = mImageSelected;
 		}
@@ -499,11 +505,11 @@ void LLButton::draw()
 		//   enabled and tentative
 		// or
 		//   disabled but checked
-		if (!mImageDisabledSelected.isNull() && ( (mEnabled && mTentative) || (!mEnabled && display_state ) ) )
+		if (!mImageDisabledSelected.isNull() && ( (mEnabled && mTentative) || (!mEnabled && pressed ) ) )
 		{
 			mImagep = mImageDisabledSelected;
 		}
-		else if (!mImageDisabled.isNull() && !mEnabled && !display_state)
+		else if (!mImageDisabled.isNull() && !mEnabled && !pressed)
 		{
 			mImagep = mImageDisabled;
 		}
@@ -516,33 +522,34 @@ void LLButton::draw()
 		// Figure out appropriate color for the text
 		LLColor4 label_color;
 
+		// label changes when button state changes, not when pressed
 		if ( mEnabled )
 		{
-			if ( !display_state )
+			if ( mToggleState )
 			{
-				label_color = mUnselectedLabelColor;
+				label_color = mSelectedLabelColor;
 			}
 			else
 			{
-				label_color = mSelectedLabelColor;
+				label_color = mUnselectedLabelColor;
 			}
 		}
 		else
 		{
-			if ( !display_state )
+			if ( mToggleState )
 			{
-				label_color = mDisabledLabelColor;
+				label_color = mDisabledSelectedLabelColor;
 			}
 			else
 			{
-				label_color = mDisabledSelectedLabelColor;
+				label_color = mDisabledLabelColor;
 			}
 		}
 
 		// Unselected label assignments
 		LLWString label;
 
-		if( display_state )
+		if( mToggleState )
 		{
 			if( mEnabled || mDisabledSelectedLabel.empty() )
 			{
@@ -591,24 +598,22 @@ void LLButton::draw()
 		// Otherwise draw basic rectangular button.
 		if( mImagep.notNull() && !mScaleImage)
 		{
-			gl_draw_image( 0, 0, mImagep, mEnabled ? mImageColor : mDisabledImageColor );
+			mImagep->draw(0, 0, mEnabled ? mImageColor : mDisabledImageColor );
 			if (mCurGlowStrength > 0.01f)
 			{
 				glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-				gl_draw_scaled_image_with_border(0, 0, 0, 0, mImagep->getWidth(), mImagep->getHeight(), mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
+				mImagep->drawSolid(0, 0, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
 				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			}
 		}
 		else
 		if ( mImagep.notNull() && mScaleImage)
 		{
-			gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(), 
-											mImagep, mEnabled ? mImageColor : mDisabledImageColor  );
+			mImagep->draw(0, 0, mRect.getWidth(), mRect.getHeight(), mEnabled ? mImageColor : mDisabledImageColor  );
 			if (mCurGlowStrength > 0.01f)
 			{
 				glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-				gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(), 
-											mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
+				mImagep->drawSolid(0, 0, mRect.getWidth(), mRect.getHeight(), LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
 				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 			}
 		}
@@ -620,13 +625,17 @@ void LLButton::draw()
 			gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE);
 		}
 
+		// let overlay image and text play well together
+		S32 text_left = mLeftHPad;
+		S32 text_right = mRect.getWidth() - mRightHPad;
+		S32 text_width = mRect.getWidth() - mLeftHPad - mRightHPad;
+
 		// draw overlay image
 		if (mImageOverlay.notNull())
 		{
-			const S32 IMG_PAD = 5;
 			// get max width and height (discard level 0)
-			S32 overlay_width = mImageOverlay->getWidth(0);
-			S32 overlay_height = mImageOverlay->getHeight(0);
+			S32 overlay_width = mImageOverlay->getWidth();
+			S32 overlay_height = mImageOverlay->getHeight();
 
 			F32 scale_factor = llmin((F32)mRect.getWidth() / (F32)overlay_width, (F32)mRect.getHeight() / (F32)overlay_height, 1.f);
 			overlay_width = llround((F32)overlay_width * scale_factor);
@@ -635,34 +644,49 @@ void LLButton::draw()
 			S32 center_x = getLocalRect().getCenterX();
 			S32 center_y = getLocalRect().getCenterY();
 
+			//FUGLY HACK FOR "DEPRESSED" BUTTONS
+			if (pressed)
+			{
+				center_y--;
+				center_x++;
+			}
+
+			// fade out overlay images on disabled buttons
+			LLColor4 overlay_color = mImageOverlayColor;
+			if (!getEnabled())
+			{
+				overlay_color.mV[VALPHA] = 0.5f;
+			}
+
 			switch(mImageOverlayAlignment)
 			{
 			case LLFontGL::LEFT:
-				gl_draw_scaled_image(
-					IMG_PAD, 
+				text_left += overlay_width + 1;
+				text_width -= overlay_width + 1;
+				mImageOverlay->draw(
+					mLeftHPad, 
 					center_y - (overlay_height / 2), 
 					overlay_width, 
 					overlay_height, 
-					mImageOverlay,
-					mImageOverlayColor);
+					overlay_color);
 				break;
 			case LLFontGL::HCENTER:
-				gl_draw_scaled_image(
+				mImageOverlay->draw(
 					center_x - (overlay_width / 2), 
 					center_y - (overlay_height / 2), 
 					overlay_width, 
 					overlay_height, 
-					mImageOverlay,
-					mImageOverlayColor);
+					overlay_color);
 				break;
 			case LLFontGL::RIGHT:
-				gl_draw_scaled_image(
-					mRect.getWidth() - IMG_PAD - overlay_width, 
+				text_right -= overlay_width + 1;				
+				text_width -= overlay_width + 1;
+				mImageOverlay->draw(
+					mRect.getWidth() - mRightHPad - overlay_width, 
 					center_y - (overlay_height / 2), 
 					overlay_width, 
 					overlay_height, 
-					mImageOverlay,
-					mImageOverlayColor);
+					overlay_color);
 				break;
 			default:
 				// draw nothing
@@ -673,28 +697,26 @@ void LLButton::draw()
 		// Draw label
 		if( !label.empty() )
 		{
-			S32 drawable_width = mRect.getWidth() - mLeftHPad - mRightHPad;
-
 			LLWString::trim(label);
 
 			S32 x;
 			switch( mHAlign )
 			{
 			case LLFontGL::RIGHT:
-				x = mRect.getWidth() - mRightHPad;
+				x = text_right;
 				break;
 			case LLFontGL::HCENTER:
 				x = mRect.getWidth() / 2;
 				break;
 			case LLFontGL::LEFT:
 			default:
-				x = mLeftHPad;
+				x = text_left;
 				break;
 			}
 
 			S32 y_offset = 2 + (mRect.getHeight() - 20)/2;
 		
-			if (pressed || display_state)
+			if (pressed)
 			{
 				y_offset--;
 				x++;
@@ -704,7 +726,7 @@ void LLButton::draw()
 				label_color,
 				mHAlign, LLFontGL::BOTTOM,
 				mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL,
-				U32_MAX, drawable_width,
+				U32_MAX, text_width,
 				NULL, FALSE, FALSE);
 		}
 
@@ -733,13 +755,11 @@ void LLButton::drawBorder(const LLColor4& color, S32 size)
 
 	if (mScaleImage)
 	{
-		gl_draw_scaled_image_with_border(left, bottom, mFixedWidth, mFixedHeight, right-left, top-bottom, 
-								mImagep, color, TRUE );
+		mImagep->drawSolid(left, bottom, right-left, top-bottom, color);
 	}
 	else
 	{
-		gl_draw_scaled_image_with_border(left, bottom, 0, 0, mImagep->getWidth() + size * 2, 
-								mImagep->getHeight() + size * 2, mImagep, color, TRUE );
+		mImagep->drawSolid(left, bottom, mImagep->getWidth() + size * 2, mImagep->getHeight() + size * 2, color);
 	}
 }
 
@@ -763,6 +783,22 @@ void LLButton::setToggleState(BOOL b)
 	}
 }
 
+void LLButton::setFlashing( BOOL b )	
+{ 
+	if (b != mFlashing)
+	{
+		mFlashing = b; 
+		mFlashingTimer.reset();
+	}
+}
+
+
+BOOL LLButton::toggleState()			
+{ 
+	setToggleState( !mToggleState ); 
+	return mToggleState; 
+}
+
 void LLButton::setValue(const LLSD& value )
 {
 	mToggleState = value.asBoolean();
@@ -770,7 +806,7 @@ void LLButton::setValue(const LLSD& value )
 
 LLSD LLButton::getValue() const
 {
-	return mToggleState;
+	return mToggleState == TRUE;
 }
 
 void LLButton::setLabel( const LLStringExplicit& label )
@@ -807,10 +843,9 @@ void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label )
 	mDisabledSelectedLabel = label;
 }
 
-void LLButton::setImageUnselectedID( const LLUUID &image_id )
-{	
-	mImageUnselectedName = "";
-	mImageUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
+void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
+{
+	mImageUnselected = image;
 }
 
 void LLButton::setImages( const LLString &image_name, const LLString &selected_name )
@@ -820,10 +855,9 @@ void LLButton::setImages( const LLString &image_name, const LLString &selected_n
 
 }
 
-void LLButton::setImageSelectedID( const LLUUID &image_id )
+void LLButton::setImageSelected(LLPointer<LLUIImage> image)
 {
-	mImageSelectedName = "";
-	mImageSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+	mImageSelected = image;
 }
 
 void LLButton::setImageColor(const LLColor4& c)		
@@ -831,19 +865,22 @@ void LLButton::setImageColor(const LLColor4& c)
 	mImageColor = c; 
 }
 
+void LLButton::setColor(const LLColor4& color)
+{
+	setImageColor(color);
+}
+
 
-void LLButton::setImageDisabledID( const LLUUID &image_id )
+void LLButton::setImageDisabled(LLPointer<LLUIImage> image)
 {
-	mImageDisabledName = "";
-	mImageDisabled = LLUI::sImageProvider->getUIImageByID(image_id);
+	mImageDisabled = image;
 	mDisabledImageColor = mImageColor;
 	mDisabledImageColor.mV[VALPHA] *= 0.5f;
 }
 
-void LLButton::setImageDisabledSelectedID( const LLUUID &image_id )
-{	
-	mImageDisabledSelectedName = "";
-	mImageDisabledSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
+{
+	mImageDisabledSelected = image;
 	mDisabledImageColor = mImageColor;
 	mDisabledImageColor.mV[VALPHA] *= 0.5f;
 }
@@ -855,11 +892,9 @@ void LLButton::setDisabledImages( const LLString &image_name, const LLString &se
 	mDisabledImageColor = c;
 }
 
-
-void LLButton::setImageHoverSelectedID( const LLUUID& image_id )
+void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
 {
-	mImageHoverSelectedName = "";
-	mImageHoverSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+	mImageHoverSelected = image;
 }
 
 void LLButton::setDisabledImages( const LLString &image_name, const LLString &selected_name)
@@ -869,10 +904,9 @@ void LLButton::setDisabledImages( const LLString &image_name, const LLString &se
 	setDisabledImages( image_name, selected_name, clr );
 }
 
-void LLButton::setImageHoverUnselectedID( const LLUUID& image_id )
+void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
 {
-	mImageHoverUnselectedName = "";
-	mImageHoverUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
+	mImageHoverUnselected = image;
 }
 
 void LLButton::setHoverImages( const LLString& image_name, const LLString& selected_name )
@@ -889,8 +923,7 @@ void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alig
 	}
 	else
 	{
-		LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name);
-		mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id);
+		mImageOverlay = LLUI::getUIImageByName(image_name);
 		mImageOverlayAlignment = alignment;
 		mImageOverlayColor = color;
 	}
@@ -903,34 +936,6 @@ void LLButton::onMouseCaptureLost()
 	mMouseDownTimer.reset();
 }
 
-//-------------------------------------------------------------------------
-// LLSquareButton
-//-------------------------------------------------------------------------
-LLSquareButton::LLSquareButton(const LLString& name, const LLRect& rect, 
-		const LLString& label,
-		const LLFontGL *font,
-		const LLString& control_name,	
-		void (*click_callback)(void*),
-		void *callback_data,
-		const LLString& selected_label )
-:	LLButton(name, rect, "","", 
-			control_name, 
-			click_callback, callback_data,
-			font,
-			label, 
-			(selected_label.empty() ? label : selected_label) )
-{ 
-	setImageUnselected("square_btn_32x128.tga");
-	//	mImageUnselected = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
-	setImageSelected("square_btn_selected_32x128.tga");
-	//	mImageSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
-	setImageDisabled("square_btn_32x128.tga");
-	//mDisabledImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
-	setImageDisabledSelected("square_btn_selected_32x128.tga");
-	//mDisabledSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
-	mImageColor = LLUI::sColorsGroup->getColor("ButtonColor");
-}
-
 //-------------------------------------------------------------------------
 // Utilities
 //-------------------------------------------------------------------------
@@ -951,37 +956,37 @@ S32 round_up(S32 grid, S32 value)
 
 void			LLButton::setImageUnselected(const LLString &image_name)
 {	
-	setImageUnselectedID(LLUI::findAssetUUIDByName(image_name));
+	setImageUnselected(LLUI::getUIImageByName(image_name));
 	mImageUnselectedName = image_name;
 }
 
 void			LLButton::setImageSelected(const LLString &image_name)
 {	
-	setImageSelectedID(LLUI::findAssetUUIDByName(image_name));
+	setImageSelected(LLUI::getUIImageByName(image_name));
 	mImageSelectedName = image_name;
 }
 
 void			LLButton::setImageHoverSelected(const LLString &image_name)
 {
-	setImageHoverSelectedID(LLUI::findAssetUUIDByName(image_name));
+	setImageHoverSelected(LLUI::getUIImageByName(image_name));
 	mImageHoverSelectedName = image_name;
 }
 
 void			LLButton::setImageHoverUnselected(const LLString &image_name)
 {
-	setImageHoverUnselectedID(LLUI::findAssetUUIDByName(image_name));
+	setImageHoverUnselected(LLUI::getUIImageByName(image_name));
 	mImageHoverUnselectedName = image_name;
 }
 
 void			LLButton::setImageDisabled(const LLString &image_name)
 {
-	setImageDisabledID(LLUI::findAssetUUIDByName(image_name));
+	setImageDisabled(LLUI::getUIImageByName(image_name));
 	mImageDisabledName = image_name;
 }
 
 void			LLButton::setImageDisabledSelected(const LLString &image_name)
 {
-	setImageDisabledSelectedID(LLUI::findAssetUUIDByName(image_name));
+	setImageDisabledSelected(LLUI::getUIImageByName(image_name));
 	mImageDisabledSelectedName = image_name;
 }
 
@@ -1009,8 +1014,6 @@ LLXMLNodePtr LLButton::getXML(bool save_children) const
 	node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected());
 	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
 	node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
-	node->createChild("border_width", TRUE)->setIntValue(mFixedWidth);
-	node->createChild("border_height", TRUE)->setIntValue(mFixedHeight);
 
 	addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,"image_unselected");
 	addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,"image_selected");
@@ -1092,8 +1095,12 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
 			label,
 			label_selected);
 
-	node->getAttributeS32("border_width", button->mFixedWidth);
-	node->getAttributeS32("border_height", button->mFixedHeight);
+	node->getAttributeS32("pad_right", button->mRightHPad);
+	node->getAttributeS32("pad_left", button->mLeftHPad);
+
+	BOOL is_toggle = button->getIsToggle();
+	node->getAttributeBOOL("toggle", is_toggle);
+	button->setIsToggle(is_toggle);
 
 	if(image_hover_selected != LLString::null) button->setImageHoverSelected(image_hover_selected);
 	
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 5f7d917b4e16a6387691c42c0b33256b61ff5527..0e140a45a6470cce38686d342eeb599a7982a1d1 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -114,11 +114,13 @@ class LLButton
 
 	F32				getHeldDownTime() const								{ return mMouseDownTimer.getElapsedTimeF32(); }
 
-	BOOL			toggleState()			{ setToggleState( !mToggleState ); return mToggleState; }
+	BOOL			getIsToggle() const { return mIsToggle; }
+	void			setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; }
+	BOOL			toggleState();
 	BOOL			getToggleState() const	{ return mToggleState; }
 	void			setToggleState(BOOL b);
 
-	void			setFlashing( BOOL b )	{ mFlashing = b; }
+	void			setFlashing( BOOL b );
 	BOOL			getFlashing() const		{ return mFlashing; }
 
 	void			setHAlign( LLFontGL::HAlign align )		{ mHAlign = align; }
@@ -128,14 +130,11 @@ class LLButton
 	const LLString	getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); }
 	const LLString	getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); }
 
-
-	// HACK to allow images to be freed when the caller knows he's done with it.
-	LLImageGL*		getImageUnselected() const							{ return mImageUnselected; }
-
 	void			setImageColor(const LLString& color_control);
-	void			setImages(const LLString &image_name, const LLString &selected_name);
 	void			setImageColor(const LLColor4& c);
-	
+	virtual void	setColor(const LLColor4& c);
+
+	void			setImages(const LLString &image_name, const LLString &selected_name);
 	void			setDisabledImages(const LLString &image_name, const LLString &selected_name);
 	void			setDisabledImages(const LLString &image_name, const LLString &selected_name, const LLColor4& c);
 	
@@ -146,7 +145,7 @@ class LLButton
 	void			setDisabledSelectedLabelColor( const LLColor4& c )	{ mDisabledSelectedLabelColor = c; }
 
 	void			setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
-	LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; }
+	LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; }
 	
 
 	virtual void	setValue(const LLSD& value );
@@ -170,16 +169,8 @@ class LLButton
 
 	static void		onHeldDown(void *userdata);  // to be called by gIdleCallbacks
 
-	void			setFixedBorder(S32 width, S32 height) { mFixedWidth = width; mFixedHeight = height; }
 	void			setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
 
-private:
-	void			setImageUnselectedID(const LLUUID &image_id);
-	void			setImageSelectedID(const LLUUID &image_id);
-	void			setImageHoverSelectedID(const LLUUID &image_id);
-	void			setImageHoverUnselectedID(const LLUUID &image_id);
-	void			setImageDisabledID(const LLUUID &image_id);
-	void			setImageDisabledSelectedID(const LLUUID &image_id);
 public:
 	void			setImageUnselected(const LLString &image_name);
 	void			setImageSelected(const LLString &image_name);
@@ -187,6 +178,14 @@ class LLButton
 	void			setImageHoverUnselected(const LLString &image_name);
 	void			setImageDisabled(const LLString &image_name);
 	void			setImageDisabledSelected(const LLString &image_name);
+
+	void			setImageUnselected(LLPointer<LLUIImage> image);
+	void			setImageSelected(LLPointer<LLUIImage> image);
+	void			setImageHoverSelected(LLPointer<LLUIImage> image);
+	void			setImageHoverUnselected(LLPointer<LLUIImage> image);
+	void			setImageDisabled(LLPointer<LLUIImage> image);
+	void			setImageDisabledSelected(LLPointer<LLUIImage> image);
+
 	void			setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
 	BOOL			getCommitOnReturn() { return mCommitOnReturn; }
 
@@ -209,27 +208,27 @@ class LLButton
 	F32				mHeldDownDelay;		// seconds, after which held-down callbacks get called
 	S32				mHeldDownFrameDelay;	// frames, after which held-down callbacks get called
 
-	LLPointer<LLImageGL>	mImageOverlay;
+	LLPointer<LLUIImage>	mImageOverlay;
 	LLFontGL::HAlign		mImageOverlayAlignment;
 	LLColor4				mImageOverlayColor;
 
-	LLPointer<LLImageGL>	mImageUnselected;
+	LLPointer<LLUIImage>	mImageUnselected;
 	LLUIString				mUnselectedLabel;
 	LLColor4				mUnselectedLabelColor;
 
-	LLPointer<LLImageGL>	mImageSelected;
+	LLPointer<LLUIImage>	mImageSelected;
 	LLUIString				mSelectedLabel;
 	LLColor4				mSelectedLabelColor;
 
-	LLPointer<LLImageGL>	mImageHoverSelected;
+	LLPointer<LLUIImage>	mImageHoverSelected;
 
-	LLPointer<LLImageGL>	mImageHoverUnselected;
+	LLPointer<LLUIImage>	mImageHoverUnselected;
 
-	LLPointer<LLImageGL>	mImageDisabled;
+	LLPointer<LLUIImage>	mImageDisabled;
 	LLUIString				mDisabledLabel;
 	LLColor4				mDisabledLabelColor;
 
-	LLPointer<LLImageGL>	mImageDisabledSelected;
+	LLPointer<LLUIImage>	mImageDisabledSelected;
 	LLUIString				mDisabledSelectedLabel;
 	LLColor4				mDisabledSelectedLabelColor;
 
@@ -254,6 +253,7 @@ class LLButton
 	LLColor4		mImageColor;
 	LLColor4		mDisabledImageColor;
 
+	BOOL			mIsToggle;
 	BOOL			mToggleState;
 	BOOL			mScaleImage;
 
@@ -267,9 +267,6 @@ class LLButton
 	S32				mLeftHPad;
 	S32				mRightHPad;
 
-	S32				mFixedWidth;
-	S32				mFixedHeight;
-
 	F32				mHoverGlowStrength;
 	F32				mCurGlowStrength;
 
@@ -278,22 +275,9 @@ class LLButton
 
 	LLString		mHelpURL;
 
-	LLPointer<LLImageGL> mImagep;
-
-	static LLFrameTimer	sFlashingTimer;
-};
+	LLPointer<LLUIImage> mImagep;
 
-class LLSquareButton
-:	public LLButton
-{
-public:
-	LLSquareButton(const LLString& name, const LLRect& rect, 
-				   const LLString& label,
-				   const LLFontGL *font = NULL,
-				   const LLString& control_name = LLString(),	
-				   void (*click_callback)(void*) = NULL,
-				   void *callback_data = NULL,
-				   const LLString& selected_label = LLString::null );
+	LLFrameTimer	mFlashingTimer;
 };
 
 // Helpful functions
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 504b342003ea62e81f4f32573d6b9b1e593abfcd..b0a7e9d27fa6984098f4ef3008b049960ffceb07 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -75,7 +75,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLString& name, const LLRect& rect,
 	}
 
 	// must be big enough to hold all children
-	setSpanChildren(TRUE);
+	setUseBoundingRect(TRUE);
 
 	mKeyboardFocusOnClick = TRUE;
 
@@ -130,6 +130,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLString& name, const LLRect& rect,
 		mButton->setDisabledImages( inactive_false_id, inactive_true_id );
 		mButton->setHoverGlowStrength(0.35f);
 	}
+	mButton->setIsToggle(TRUE);
 	mButton->setToggleState( initial_value );
 	mButton->setFollowsLeft();
 	mButton->setFollowsBottom();
@@ -150,16 +151,11 @@ void LLCheckBoxCtrl::onButtonPress( void *userdata )
 
 	if (self->mRadioStyle)
 	{
-		if (!self->getValue())
-		{
-			self->setValue(TRUE);
-		}
-	}
-	else
-	{
-		self->toggle();
+		self->setValue(TRUE);
 	}
+
 	self->setControlValue(self->getValue());
+	// HACK: because buttons don't normally commit
 	self->onCommit();
 
 	if (self->mKeyboardFocusOnClick)
@@ -232,14 +228,13 @@ void LLCheckBoxCtrl::draw()
 //virtual
 void LLCheckBoxCtrl::setValue(const LLSD& value )
 {
-	mSetValue = value.asBoolean();
-	mButton->setToggleState( mSetValue );
+	mButton->setValue( value );
 }
 
 //virtual
 LLSD LLCheckBoxCtrl::getValue() const
 {
-	return mButton->getToggleState();
+	return mButton->getValue();
 }
 
 void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label )
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 5f76cfc94b2f863f2000e31a1a4a7b9375db353c..6063fc155aba418b556f7c689fcbc44e3153892c 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -55,17 +55,16 @@
 // Globals
 S32 LLCOMBOBOX_HEIGHT = 0;
 S32 LLCOMBOBOX_WIDTH = 0;
- 
+S32 MAX_COMBO_WIDTH = 500;
+
 LLComboBox::LLComboBox(	const LLString& name, const LLRect &rect, const LLString& label,
 	void (*commit_callback)(LLUICtrl*,void*),
 	void *callback_userdata
 	)
 :	LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, 
 			 FOLLOWS_LEFT | FOLLOWS_TOP),
-	mDrawArrow(TRUE),
 	mTextEntry(NULL),
 	mArrowImage(NULL),
-	mArrowImageWidth(8),
 	mAllowTextEntry(FALSE),
 	mMaxChars(20),
 	mTextEntryTentative(TRUE),
@@ -73,55 +72,43 @@ LLComboBox::LLComboBox(	const LLString& name, const LLRect &rect, const LLString
 	mPrearrangeCallback( NULL ),
 	mTextEntryCallback( NULL )
 {
-	// For now, all comboboxes don't take keyboard focus when clicked.
-	// This might change if it is part of a modal dialog.
-	// mKeyboardFocusOnClick = FALSE;
-
-	// Revert to standard behavior.  When this control's parent is hidden, it needs to
-	// hide this ctrl--which won't just happen automatically since when LLComboBox is 
-	// showing its list, it's also set to TopCtrl.  When keyboard focus is cleared all
-	// controls (including this one) know that they are no longer editing.
-	mKeyboardFocusOnClick = TRUE;
-
-	LLRect r;
-	r.setOriginAndSize(0, 0, rect.getWidth(), rect.getHeight());
-
 	// Always use text box 
 	// Text label button
-	mButton = new LLSquareButton("comboxbox button",
-								 r, label, NULL, LLString::null,
+	mButton = new LLButton("comboxbox button",
+								 LLRect(), label, NULL, LLString::null,
 								 NULL, this);
+	mButton->setImageUnselected("square_btn_32x128.tga");
+	mButton->setImageSelected("square_btn_selected_32x128.tga");
+	mButton->setImageDisabled("square_btn_32x128.tga");
+	mButton->setImageDisabledSelected("square_btn_selected_32x128.tga");
+	mButton->setScaleImage(TRUE);
+
 	mButton->setMouseDownCallback(onButtonDown);
 	mButton->setFont(LLFontGL::sSansSerifSmall);
 	mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
 	mButton->setHAlign( LLFontGL::LEFT );
-
-	const S32 ARROW_WIDTH = 16;
-	mButton->setRightHPad( ARROW_WIDTH );
+	mButton->setRightHPad(2);
 	addChild(mButton);
 
-	// Default size, will be set by arrange() call in button callback. 
-	S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
-	r.setOriginAndSize(0, 16, list_width, 220);
-
 	// disallow multiple selection
 	mList = new LLScrollListCtrl(
-		"ComboBox", r, 
+		"ComboBox", LLRect(), 
 		&LLComboBox::onItemSelected, this, FALSE);
 	mList->setVisible(FALSE);
 	mList->setBgWriteableColor( LLColor4(1,1,1,1) );
 	mList->setCommitOnKeyboardMovement(FALSE);
-	mList->setFocusChangedCallback(onListFocusChanged);
 	addChild(mList);
 
 	LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
 	mBorder = new LLViewBorder( "combo border", border_rect );
 	addChild( mBorder );
-	mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
+	mBorder->setFollowsAll();
 
 	LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") );
-	mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id);
-	mArrowImageWidth = llmax(8,mArrowImage->getWidth(0)); // In case image hasn't loaded yet
+	mArrowImage = LLUI::sImageProvider->getImageByID(arrow_image_id);
+	mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
+
+	updateLayout();
 }
 
 
@@ -155,7 +142,7 @@ LLXMLNodePtr LLComboBox::getXML(bool save_children) const
 			LLSD value = item->getValue();
 			item_node->createChild("value", TRUE)->setStringValue(value.asString());
 			item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
-			item_node->setStringValue(cell->getText());
+			item_node->setStringValue(cell->getValue().asString());
 		}
 	}
 
@@ -272,34 +259,42 @@ void	LLComboBox::resetDirty()
 
 
 // add item "name" to menu
-void LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
+LLScrollListItem* LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
 {
-	mList->addSimpleItem(name, pos, enabled);
+	LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled);
 	mList->selectFirstItem();
+	return item;
 }
 
 // add item "name" with a unique id to menu
-void LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
 {
-	mList->addSimpleItem(name, LLSD(id), pos, enabled);
+	LLScrollListItem* item = mList->addSimpleItem(name, LLSD(id), pos, enabled);
 	mList->selectFirstItem();
+	return item;
 }
 
 // add item "name" with attached userdata
-void LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
 {
 	LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled);
 	item->setUserdata( userdata );
 	mList->selectFirstItem();
+	return item;
 }
 
 // add item "name" with attached generic data
-void LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
 {
-	mList->addSimpleItem(name, value, pos, enabled);
+	LLScrollListItem* item = mList->addSimpleItem(name, value, pos, enabled);
 	mList->selectFirstItem();
+	return item;
 }
 
+LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos)
+{
+	return mList->addSeparator(pos);
+}
 
 void LLComboBox::sortByName()
 {
@@ -335,9 +330,9 @@ void LLComboBox::setValue(const LLSD& value)
 	}
 }
 
-const LLString& LLComboBox::getSimple() const
+const LLString LLComboBox::getSimple() const
 {
-	const LLString& res = mList->getSimpleSelectedItem();
+	const LLString res = mList->getSimpleSelectedItem();
 	if (res.empty() && mAllowTextEntry)
 	{
 		return mTextEntry->getText();
@@ -348,7 +343,7 @@ const LLString& LLComboBox::getSimple() const
 	}
 }
 
-const LLString& LLComboBox::getSimpleSelectedItem(S32 column) const
+const LLString LLComboBox::getSimpleSelectedItem(S32 column) const
 {
 	return mList->getSimpleSelectedItem(column);
 }
@@ -373,7 +368,7 @@ LLSD LLComboBox::getValue() const
 
 void LLComboBox::setLabel(const LLStringExplicit& name)
 {
-	if ( mAllowTextEntry )
+	if ( mTextEntry )
 	{
 		mTextEntry->setText(name);
 		if (mList->selectSimpleItem(name, FALSE))
@@ -385,7 +380,8 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
 			mTextEntry->setTentative(mTextEntryTentative);
 		}
 	}
-	else
+	
+	if (!mAllowTextEntry)
 	{
 		mButton->setLabelUnselected(name);
 		mButton->setLabelSelected(name);
@@ -433,16 +429,21 @@ void LLComboBox::onFocusLost()
 	LLUICtrl::onFocusLost();
 }
 
+void LLComboBox::onLostTop()
+{
+	hideList();
+}
+
+
 void LLComboBox::setButtonVisible(BOOL visible)
 {
 	mButton->setVisible(visible);
-	mDrawArrow = visible;
 	if (mTextEntry)
 	{
 		LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
 		if (visible)
 		{
-			text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+			text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
 		}
 		//mTextEntry->setRect(text_entry_rect);
 		mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -457,22 +458,8 @@ void LLComboBox::draw()
 
 		mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/);
 
-		// Draw children
+		// Draw children normally
 		LLUICtrl::draw();
-
-		if (mDrawArrow)
-		{
-			// Paste the graphic on the right edge
-			if (!mArrowImage.isNull())
-			{
-				S32 arrow_height = llmin(mRect.getHeight(), mArrowImage->getHeight());
-				S32 arrow_width = llround((F32)mArrowImage->getWidth() * ((F32)arrow_height / (F32)mArrowImage->getHeight()));
-
-				S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton");
-
-				gl_draw_scaled_image( left, 0, arrow_width, arrow_height, mArrowImage, LLColor4::white);
-			}
-		}
 	}
 }
 
@@ -497,6 +484,67 @@ S32 LLComboBox::getCurrentIndex() const
 }
 
 
+void LLComboBox::updateLayout()
+{
+	LLRect rect = getLocalRect();
+	if (mAllowTextEntry)
+	{
+		S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
+		mButton->setRect(LLRect( mRect.getWidth() - llmax(8,mArrowImage->getWidth(0)) - 2 * shadow_size,
+								rect.mTop, rect.mRight, rect.mBottom));
+		mButton->setTabStop(FALSE);
+
+		if (!mTextEntry)
+		{
+			LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
+			text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+			// clear label on button
+			LLString cur_label = mButton->getLabelSelected();
+			mTextEntry = new LLLineEditor("combo_text_entry",
+										text_entry_rect,
+										"",
+										LLFontGL::sSansSerifSmall,
+										mMaxChars,
+										onTextCommit,
+										onTextEntry,
+										NULL,
+										this,
+										NULL,		// prevalidate func
+										LLViewBorder::BEVEL_NONE,
+										LLViewBorder::STYLE_LINE,
+										0);	// no border
+			mTextEntry->setSelectAllonFocusReceived(TRUE);
+			mTextEntry->setHandleEditKeysDirectly(TRUE);
+			mTextEntry->setCommitOnFocusLost(FALSE);
+			mTextEntry->setText(cur_label);
+			mTextEntry->setIgnoreTab(TRUE);
+			mTextEntry->setFollowsAll();
+			addChild(mTextEntry);
+		}
+		else
+		{
+			mTextEntry->setVisible(TRUE);
+			mTextEntry->setMaxTextLength(mMaxChars);
+		}
+
+		// clear label on button
+		setLabel(LLString::null);
+
+		mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
+	}
+	else if (!mAllowTextEntry)
+	{
+		mButton->setRect(rect);
+		mButton->setTabStop(TRUE);
+
+		if (mTextEntry)
+		{
+			mTextEntry->setVisible(FALSE);
+		}
+		mButton->setFollowsAll();
+	}
+}
+
 void* LLComboBox::getCurrentUserdata()
 {
 	LLScrollListItem* item = mList->getFirstSelected();
@@ -514,7 +562,7 @@ void LLComboBox::showList()
 	LLCoordWindow window_size;
 	getWindow()->getSize(&window_size);
 	//HACK: shouldn't have to know about scale here
-	mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
+	mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
 
 	// Make sure that we can see the whole list
 	LLRect root_view_local;
@@ -523,7 +571,9 @@ void LLComboBox::showList()
 	
 	LLRect rect = mList->getRect();
 
-	S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
+	S32 min_width = mRect.getWidth();
+	S32 max_width = llmax(min_width, MAX_COMBO_WIDTH);
+	S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width);
 
 	if (mListPosition == BELOW)
 	{
@@ -583,12 +633,6 @@ void LLComboBox::showList()
 		mList->translate(0, -y);
 	}
 
-	// pass mouse capture on to list if button is depressed
-	if (mButton->hasMouseCapture())
-	{
-		gFocusMgr.setMouseCapture(mList);
-	}
-	
 	// NB: this call will trigger the focuslost callback which will hide the list, so do it first
 	// before finally showing the list
 
@@ -604,24 +648,29 @@ void LLComboBox::showList()
 	mButton->setToggleState(TRUE);
 	mList->setVisible(TRUE);
 	
-	gFocusMgr.setTopCtrl(mList);
+	setUseBoundingRect(TRUE);
+	gFocusMgr.setTopCtrl(this);
 }
 
 void LLComboBox::hideList()
 {
+	//*HACK: store the original value explicitly somewhere, not just in label
+	LLString orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected();
+
+	// assert selection in list
+	mList->selectSimpleItem(orig_selection, FALSE);
+
 	mButton->setToggleState(FALSE);
 	mList->setVisible(FALSE);
 	mList->highlightNthItem(-1);
 
-	if( gFocusMgr.getTopCtrl() == mList )
+	setUseBoundingRect(FALSE);
+	if( gFocusMgr.getTopCtrl() == this )
 	{
 		gFocusMgr.setTopCtrl(NULL);
 	}
-
-	//mList->setFocus(FALSE);
 }
 
-
 //------------------------------------------------------------------
 // static functions
 //------------------------------------------------------------------
@@ -650,21 +699,20 @@ void LLComboBox::onButtonDown(void *userdata)
 			self->showList();
 		}
 
-		if (self->mKeyboardFocusOnClick && !self->hasFocus())
+		self->setFocus( TRUE );
+
+		// pass mouse capture on to list if button is depressed
+		if (self->mButton->hasMouseCapture())
 		{
-			self->setFocus( TRUE );
+			gFocusMgr.setMouseCapture(self->mList);
 		}
 	}
 	else
 	{
-		// hide and release keyboard focus
 		self->hideList();
-
-		self->onCommit();
 	}
-}
-
 
+}
 
 // static
 void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
@@ -672,7 +720,7 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
 	// Note: item is the LLScrollListCtrl
 	LLComboBox *self = (LLComboBox *) userdata;
 
-	const LLString& name = self->mList->getSimpleSelectedItem();
+	const LLString name = self->mList->getSimpleSelectedItem();
 
 	S32 cur_id = self->getCurrentIndex();
 	if (cur_id != -1)
@@ -681,40 +729,24 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
 
 		if (self->mAllowTextEntry)
 		{
-			gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL);
+			gFocusMgr.setKeyboardFocus(self->mTextEntry);
 			self->mTextEntry->selectAll();
 		}
 	}
 	else
 	{
 		// invalid selection, just restore existing value
-		self->mList->selectSimpleItem(self->mButton->getLabelSelected());
+		LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
+
+		self->mList->selectSimpleItem(orig_selection);
 	}
 	self->onCommit();
 
 	self->hideList();
 }
 
-// static
-void LLComboBox::onListFocusChanged(LLUICtrl* list, void* user_data)
-{
-	LLComboBox *self = (LLComboBox *) list->getParent();
-	// user not manipulating list or clicking on drop down button
-	if (!self->mList->hasFocus() && !self->mButton->hasMouseCapture())
-	{
-		//*HACK: store the original value explicitly somewhere, not just in label
-		LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
-
-		self->hideList();
-
-		// reassert original selection
-		self->mList->selectSimpleItem(orig_selection, FALSE);
-	}
-}
-
 BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
 {
-
     LLString tool_tip;
 
 	if (LLUI::sShowXUINames)
@@ -726,23 +758,19 @@ BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_
 		tool_tip = mToolTipMsg;
 	}
 
-	if( getVisible() && pointInView( x, y ) ) 
+	if( !tool_tip.empty() )
 	{
-		if( !tool_tip.empty() )
-		{
-			msg = tool_tip;
-
-			// Convert rect local to screen coordinates
-			localPointToScreen( 
-				0, 0, 
-				&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
-			localPointToScreen(
-				mRect.getWidth(), mRect.getHeight(),
-				&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
-		}
-		return TRUE;
+		msg = tool_tip;
+
+		// Convert rect local to screen coordinates
+		localPointToScreen( 
+			0, 0, 
+			&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+		localPointToScreen(
+			mRect.getWidth(), mRect.getHeight(),
+			&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
 	}
-	return FALSE;
+	return TRUE;
 }
 
 BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
@@ -793,63 +821,11 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent
 
 void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
 {
-	LLRect rect( 0, mRect.getHeight(), mRect.getWidth(), 0);
-	if (allow && !mAllowTextEntry)
-	{
-		S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
-		mButton->setRect(LLRect( mRect.getWidth() - mArrowImageWidth - 2 * shadow_size,
-								rect.mTop, rect.mRight, rect.mBottom));
-		mButton->setTabStop(FALSE);
-
-		// clear label on button
-		LLString cur_label = mButton->getLabelSelected();
-		setLabel(LLString::null);
-		if (!mTextEntry)
-		{
-			LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
-			text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
-			mTextEntry = new LLLineEditor("combo_text_entry",
-										text_entry_rect,
-										"",
-										LLFontGL::sSansSerifSmall,
-										max_chars,
-										onTextCommit,
-										onTextEntry,
-										NULL,
-										this,
-										NULL,		// prevalidate func
-										LLViewBorder::BEVEL_NONE,
-										LLViewBorder::STYLE_LINE,
-										0);	// no border
-			mTextEntry->setSelectAllonFocusReceived(TRUE);
-			mTextEntry->setHandleEditKeysDirectly(TRUE);
-			mTextEntry->setCommitOnFocusLost(FALSE);
-			mTextEntry->setText(cur_label);
-			mTextEntry->setIgnoreTab(TRUE);
-			mTextEntry->setFollowsAll();
-			addChild(mTextEntry);
-			mMaxChars = max_chars;
-		}
-		else
-		{
-			mTextEntry->setVisible(TRUE);
-		}
-
-		mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
-	}
-	else if (!allow && mAllowTextEntry)
-	{
-		mButton->setRect(rect);
-		mButton->setTabStop(TRUE);
-
-		if (mTextEntry)
-		{
-			mTextEntry->setVisible(FALSE);
-		}
-		mButton->setFollowsAll();
-	}
 	mAllowTextEntry = allow;
-	mTextEntryTentative = set_tentative;	
+	mTextEntryTentative = set_tentative;
+	mMaxChars = max_chars;
+
+	updateLayout();
 }
 
 void LLComboBox::setTextEntry(const LLStringExplicit& text)
@@ -993,6 +969,10 @@ void LLComboBox::setFocus(BOOL b)
 	if (b)
 	{
 		mList->clearSearchString();
+		if (mList->getVisible())
+		{
+			mList->setFocus(TRUE);
+		}
 	}
 }
 
@@ -1097,3 +1077,155 @@ BOOL LLComboBox::operateOnAll(EOperation op)
 	}
 	return FALSE;
 }
+
+
+
+//
+// LLFlyoutButton
+//
+
+const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
+
+LLFlyoutButton::LLFlyoutButton(
+		const LLString& name, 
+		const LLRect &rect,
+		const LLString& label,
+		void (*commit_callback)(LLUICtrl*, void*) ,
+		void *callback_userdata)
+:		LLComboBox(name, rect, LLString::null, commit_callback, callback_userdata),
+		mToggleState(FALSE),
+		mActionButton(NULL)
+{
+	// Always use text box 
+	// Text label button
+	mActionButton = new LLButton("flyout_button_main",
+								 LLRect(), label, NULL, LLString::null,
+								 NULL, this);
+	mActionButton->setScaleImage(TRUE);
+
+	mActionButton->setClickedCallback(onActionButtonClick);
+	mActionButton->setFollowsAll();
+	mActionButton->setHAlign( LLFontGL::HCENTER );
+	mActionButton->setLabel(label);
+	addChild(mActionButton);
+
+	mActionButtonImage = LLUI::getUIImageByName("flyout_btn_left.tga");
+	mExpanderButtonImage = LLUI::getUIImageByName("flyout_btn_right.tga");
+	mActionButtonImageSelected = LLUI::getUIImageByName("flyout_btn_left_selected.tga");
+	mExpanderButtonImageSelected = LLUI::getUIImageByName("flyout_btn_right_selected.tga");
+
+	mActionButton->setImageSelected(mActionButtonImageSelected);
+	mActionButton->setImageUnselected(mActionButtonImage);
+	mActionButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
+	mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
+
+	mButton->setImageSelected(mExpanderButtonImageSelected);
+	mButton->setImageUnselected(mExpanderButtonImage);
+	mButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
+	mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
+	mButton->setRightHPad(6);
+
+	mBorder->setVisible(FALSE);
+
+	updateLayout();
+}
+
+//static 
+LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+{
+	LLString name = "flyout_button";
+	node->getAttributeString("name", name);
+
+	LLString label("");
+	node->getAttributeString("label", label);
+
+	LLRect rect;
+	createRect(node, rect, parent, LLRect());
+
+	LLUICtrlCallback callback = NULL;
+
+	LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
+							rect, 
+							label,
+							callback,
+							NULL);
+
+	LLString list_position;
+	node->getAttributeString("list_position", list_position);
+	if (list_position == "below")
+	{
+		flyout_button->mListPosition = BELOW;
+	}
+	else if (list_position == "above")
+	{
+		flyout_button->mListPosition = ABOVE;
+	}
+	
+
+	flyout_button->initFromXML(node, parent);
+
+	LLXMLNodePtr child;
+	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+	{
+		if (child->hasName("flyout_button_item"))
+		{
+			LLString label = child->getTextContents();
+
+			LLString value = label;
+			child->getAttributeString("value", value);
+
+			flyout_button->add(label, LLSD(value) );
+		}
+	}
+
+	flyout_button->updateLayout();
+
+	return flyout_button;
+}
+
+void LLFlyoutButton::updateLayout()
+{
+	LLComboBox::updateLayout();
+
+	mButton->setOrigin(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
+	mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
+	mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+	mButton->setTabStop(FALSE);
+	mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
+
+	mActionButton->setOrigin(0, 0);
+	mActionButton->reshape(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
+}
+
+//static 
+void LLFlyoutButton::onActionButtonClick(void *user_data)
+{
+	LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
+	// remember last list selection?
+	buttonp->mList->deselect();
+	buttonp->onCommit();
+}
+
+void LLFlyoutButton::draw()
+{
+	mActionButton->setToggleState(mToggleState);
+	mButton->setToggleState(mToggleState);
+
+	//FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
+	// the label reflects the last selected item, for now we have to manually remove the label
+	mButton->setLabel(LLString::null);
+	LLComboBox::draw();	
+}
+
+void LLFlyoutButton::setEnabled(BOOL enabled)
+{
+	mActionButton->setEnabled(enabled);
+	LLComboBox::setEnabled(enabled);
+}
+
+
+void LLFlyoutButton::setToggleState(BOOL state)
+{
+	mToggleState = state;
+}
+
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index ff17d2874f32f22e1b1093a1c04e16eb962eb878..6e77007aef1d58abb97e3dbf5bd036e1680924b0 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -80,6 +80,7 @@ class LLComboBox
 
 	virtual void	draw();
 	virtual void	onFocusLost();
+	virtual void	onLostTop();
 
 	virtual void	setEnabled(BOOL enabled);
 
@@ -107,10 +108,11 @@ class LLComboBox
 	void			setAllowTextEntry(BOOL allow, S32 max_chars = 50, BOOL make_tentative = TRUE);
 	void			setTextEntry(const LLStringExplicit& text);
 
-	void			add(const LLString& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);	// add item "name" to menu
-	void			add(const LLString& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
-	void			add(const LLString& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
-	void			add(const LLString& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+	LLScrollListItem*	add(const LLString& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);	// add item "name" to menu
+	LLScrollListItem*	add(const LLString& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+	LLScrollListItem*	add(const LLString& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+	LLScrollListItem*	add(const LLString& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+	LLScrollListItem*	addSeparator(EAddPosition pos = ADD_BOTTOM);
 	BOOL			remove( S32 index );	// remove item by index, return TRUE if found and removed
 	void			removeall() { clearRows(); }
 
@@ -119,9 +121,9 @@ class LLComboBox
 	// Select current item by name using selectSimpleItem.  Returns FALSE if not found.
 	BOOL			setSimple(const LLStringExplicit& name);
 	// Get name of current item. Returns an empty string if not found.
-	const LLString&	getSimple() const;
+	const LLString	getSimple() const;
 	// Get contents of column x of selected row
-	const LLString& getSimpleSelectedItem(S32 column = 0) const;
+	const LLString getSimpleSelectedItem(S32 column = 0) const;
 
 	// Sets the label, which doesn't have to exist in the label.
 	// This is probably a UI abuse.
@@ -132,6 +134,8 @@ class LLComboBox
 	BOOL			setCurrentByIndex( S32 index );
 	S32				getCurrentIndex() const;
 
+	virtual void	updateLayout();
+
 	//========================================================================
 	LLCtrlSelectionInterface* getSelectionInterface()	{ return (LLCtrlSelectionInterface*)this; };
 	LLCtrlListInterface* getListInterface()				{ return (LLCtrlListInterface*)this; };
@@ -172,7 +176,6 @@ class LLComboBox
 
 	static void		onButtonDown(void *userdata);
 	static void		onItemSelected(LLUICtrl* item, void *userdata);
-	static void		onListFocusChanged(LLUICtrl* item, void *userdata);
 	static void		onTextEntry(LLLineEditor* line_editor, void* user_data);
 	static void		onTextCommit(LLUICtrl* caller, void* user_data);
 
@@ -183,12 +186,10 @@ class LLComboBox
 protected:
 	LLButton*			mButton;
 	LLScrollListCtrl*	mList;
+	S32					mButtonPadding;
 	LLViewBorder*		mBorder;
-	BOOL				mKeyboardFocusOnClick;
-	BOOL				mDrawArrow;
 	LLLineEditor*		mTextEntry;
 	LLPointer<LLImageGL>	mArrowImage;
-	S32					mArrowImageWidth;
 	BOOL				mAllowTextEntry;
 	S32					mMaxChars;
 	BOOL				mTextEntryTentative;
@@ -197,4 +198,36 @@ class LLComboBox
 	void				(*mTextEntryCallback)(LLLineEditor*, void*);
 };
 
+class LLFlyoutButton : public LLComboBox
+{
+public:
+	LLFlyoutButton(
+		const LLString& name, 
+		const LLRect &rect,
+		const LLString& label,
+		void (*commit_callback)(LLUICtrl*, void*) = NULL,
+		void *callback_userdata = NULL);
+
+	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_FLYOUT_BUTTON; }
+	virtual LLString getWidgetTag() const { return LL_FLYOUT_BUTTON_TAG; }
+
+	virtual void	updateLayout();
+	virtual void	draw();
+	virtual void	setEnabled(BOOL enabled);
+
+	void setToggleState(BOOL state);
+
+	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	static void		onActionButtonClick(void *userdata);
+	static void		onSelectAction(LLUICtrl* ctrl, void *userdata);
+
+protected:
+	LLButton*				mActionButton;
+	LLPointer<LLUIImage>	mActionButtonImage;
+	LLPointer<LLUIImage>	mExpanderButtonImage;
+	LLPointer<LLUIImage>	mActionButtonImageSelected;
+	LLPointer<LLUIImage>	mExpanderButtonImageSelected;
+	BOOL					mToggleState;
+};
+
 #endif
diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h
index 50d199fac596f83af5a77595e341f050e6b134e0..cd3ce04718d177b607b58ae09c2848b7e8505463 100644
--- a/indra/llui/lldraghandle.h
+++ b/indra/llui/lldraghandle.h
@@ -54,7 +54,6 @@ class LLDragHandle : public LLView
 
 	virtual void	setTitle( const LLString& title ) = 0;
 	virtual const LLString&	getTitle() const = 0;
-	virtual void	draw() = 0;
 	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) = 0;
 
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 6f1c281eb24c60d41e0902f0b1cc98543f99d274..59741a799af9703cd7bf1ebd5ef8eef402e268ea 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -128,7 +128,11 @@ LLFloater::handle_map_t	LLFloater::sFloaterMap;
 
 LLFloaterView* gFloaterView = NULL;
 
-LLFloater::LLFloater() 
+LLFloater::LLFloater() :
+	//FIXME: we should initialize *all* member variables here
+	mResizable(FALSE),
+	mDragOnLeft(FALSE)
+
 {
 	// automatically take focus when opened
 	mAutoFocus = TRUE;
@@ -215,9 +219,14 @@ void LLFloater::init(const LLString& title,
 	}
 	mButtonScale = 1.f;
 
-	LLPanel::deleteAllChildren();
+	BOOL need_border = mBorder != NULL;
+
+	// this will delete mBorder too
+	deleteAllChildren();
+	// make sure we don't have a pointer to an old, deleted border	
+	mBorder = NULL;
 	//sjb: HACK! we had a border which was just deleted, so re-create it
-	if (mBorder != NULL)
+	if (need_border)
 	{
 		addBorder();
 	}
@@ -609,7 +618,7 @@ void LLFloater::releaseFocus()
 
 	if( gFocusMgr.childHasKeyboardFocus( this ) )
 	{
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
+		gFocusMgr.setKeyboardFocus(NULL);
 	}
 
 	if( gFocusMgr.childHasMouseCapture( this ) )
@@ -1023,13 +1032,10 @@ void LLFloater::setHost(LLMultiFloater* host)
 		{
 			mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE;
 		}
-
-		mIsFocusRoot = FALSE;
 	}
 	else if (!mHostHandle.isDead() && !host)
 	{
 		mButtonScale = 1.f;
-		mIsFocusRoot = TRUE;
 		//mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE;
 	}
 	updateButtons();
@@ -1257,6 +1263,7 @@ void LLFloater::show(LLFloater* floaterp)
 {
 	if (floaterp) 
 	{
+		gFocusMgr.triggerFocusFlash();
 		floaterp->open();
 		if (floaterp->getHost())
 		{
@@ -2594,9 +2601,9 @@ void LLMultiFloater::draw()
 		for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
 		{
 			LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
-			if (floaterp->getTitle() != mTabContainer->getPanelTitle(i))
+			if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
 			{
-				mTabContainer->setPanelTitle(i, floaterp->getTitle());
+				mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
 			}
 		}
 		LLFloater::draw();
@@ -2714,7 +2721,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
 
 	if ( select_added_floater )
 	{
-		mTabContainer->selectLastTab();
+		mTabContainer->selectTabPanel(floaterp);
 	}
 
 	floaterp->setHost(this);
@@ -2959,8 +2966,9 @@ void LLMultiFloater::updateResizeLimits()
 		// make sure upper left corner doesn't move
 		translate(0, cur_height - mRect.getHeight());
 
-		// Try to keep whole view onscreen, don't allow partial offscreen.
-		gFloaterView->adjustToFitScreen(this, FALSE);
+		// make sure this window is visible on screen when it has been modified
+		// (tab added, etc)
+		gFloaterView->adjustToFitScreen(this, TRUE);
 	}
 }
 
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 6358ccbdd7b222330ac33132f081fb9020f9bcf3..e3337eb5882a475532abda896907fd894b9daf87 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -42,11 +42,10 @@ LLFocusMgr gFocusMgr;
 LLFocusMgr::LLFocusMgr()
 	:
 	mLockedView( NULL ),
-	mKeyboardLockedFocusLostCallback( NULL ),
 	mMouseCaptor( NULL ),
 	mKeyboardFocus( NULL ),
+	mLastKeyboardFocus( NULL ),
 	mDefaultKeyboardFocus( NULL ),
-	mKeyboardFocusLostCallback( NULL ),
 	mTopCtrl( NULL ),
 	mFocusWeight(0.f),
 	mAppHasFocus(TRUE)   // Macs don't seem to notify us that we've gotten focus, so default to true
@@ -75,12 +74,11 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
 		if (view == mLockedView)
 		{
 			mLockedView = NULL;
-			mKeyboardLockedFocusLostCallback = NULL;
-			setKeyboardFocus( NULL, NULL );
+			setKeyboardFocus( NULL );
 		}
 		else
 		{
-			setKeyboardFocus( mLockedView, mKeyboardLockedFocusLostCallback );
+			setKeyboardFocus( mLockedView );
 		}
 	}
 
@@ -91,7 +89,7 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
 }
 
 
-void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focus_lost, BOOL lock)
+void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock)
 {
 	if (mLockedView && 
 		(new_focus == NULL || 
@@ -101,28 +99,27 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu
 		// or one of its descendants
 		return;
 	}
-	FocusLostCallback old_callback = mKeyboardFocusLostCallback;
-	mKeyboardFocusLostCallback = on_focus_lost;
 
 	//llinfos << "Keyboard focus handled by " << (new_focus ? new_focus->getName() : "nothing") << llendl;
 
 	if( new_focus != mKeyboardFocus )
 	{
-		LLUICtrl* old_focus = mKeyboardFocus;
+		mLastKeyboardFocus = mKeyboardFocus;
 		mKeyboardFocus = new_focus;
 
+		if( mLastKeyboardFocus )
+		{
+			mLastKeyboardFocus->onFocusLost();
+		}
+
 		// clear out any existing flash
 		if (new_focus)
 		{
 			mFocusWeight = 0.f;
+			new_focus->onFocusReceived();
 		}
 		mFocusTimer.reset();
 
-		if( old_callback )
-		{
-			old_callback( old_focus );
-		}
-
 		#ifdef _DEBUG
 			mKeyboardFocusName = new_focus ? new_focus->getName() : "none";
 		#endif
@@ -204,13 +201,11 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( LLView* focus )
 	if (focus == mLockedView)
 	{
 		mLockedView = NULL;
-		mKeyboardLockedFocusLostCallback = NULL;
 	}
 
 	if( mKeyboardFocus == focus )
 	{
 		mKeyboardFocus = NULL;
-		mKeyboardFocusLostCallback = NULL;
 		#ifdef _DEBUG
 			mKeyboardFocusName = "none";
 		#endif
@@ -293,13 +288,19 @@ BOOL LLFocusMgr::childIsTopCtrl( LLView* parent )
 // set new_top = NULL to release top_view.
 void LLFocusMgr::setTopCtrl( LLUICtrl* new_top  )
 {
-	if( new_top != mTopCtrl )
+	LLUICtrl* old_top = mTopCtrl;
+	if( new_top != old_top )
 	{
 		mTopCtrl = new_top;
 
 		#ifdef _DEBUG
 			mTopCtrlName = new_top ? new_top->getName() : "none";
 		#endif
+
+		if (old_top)
+		{
+			old_top->onLostTop();
+		}
 	}
 }
 
@@ -317,13 +318,11 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( LLUICtrl* top_view )
 void LLFocusMgr::lockFocus()
 {
 	mLockedView = mKeyboardFocus; 
-	mKeyboardLockedFocusLostCallback = mKeyboardFocusLostCallback; 
 }
 
 void LLFocusMgr::unlockFocus()
 {
 	mLockedView = NULL; 
-	mKeyboardLockedFocusLostCallback = NULL;
 }
 
 F32 LLFocusMgr::getFocusFlashAmt()
@@ -356,9 +355,9 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
 	}
 	
 	// release focus from "top ctrl"s, which generally hides them
-	if (!focus && mTopCtrl && mTopCtrl->hasFocus())
+	if (!focus && mTopCtrl)
 	{
-		mTopCtrl->setFocus(FALSE);
+		setTopCtrl(NULL);
 	}
 	mAppHasFocus = focus; 
 }
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 1c25153fbe00954a5ecca56e78fe3ad801761cae..20dc21fc3a92fa2280f3bd112541f41690972877 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -44,8 +44,6 @@ class LLMouseHandler;
 class LLFocusMgr
 {
 public:
-	typedef void (*FocusLostCallback)(LLUICtrl*);
-
 	LLFocusMgr();
 	~LLFocusMgr();
 
@@ -56,11 +54,11 @@ class LLFocusMgr
 	BOOL			childHasMouseCapture( LLView* parent );
 
 	// Keyboard Focus
-	void			setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focus_lost, BOOL lock = FALSE);		// new_focus = NULL to release the focus.
+	void			setKeyboardFocus(LLUICtrl* new_focus, BOOL lock = FALSE);		// new_focus = NULL to release the focus.
 	LLUICtrl*		getKeyboardFocus() const { return mKeyboardFocus; }  
+	LLUICtrl*		getLastKeyboardFocus() const { return mLastKeyboardFocus; }  
 	BOOL			childHasKeyboardFocus( const LLView* parent ) const;
 	void			removeKeyboardFocusWithoutCallback( LLView* focus );
-	FocusLostCallback getFocusCallback() { return mKeyboardFocusLostCallback; }
 	F32				getFocusTime() const { return mFocusTimer.getElapsedTimeF32(); }
 	F32				getFocusFlashAmt();
 	LLColor4		getFocusColor();
@@ -90,15 +88,14 @@ class LLFocusMgr
 
 protected:
 	LLUICtrl*			mLockedView;
-	FocusLostCallback mKeyboardLockedFocusLostCallback;
 
 	// Mouse Captor
 	LLMouseHandler*		mMouseCaptor;				// Mouse events are premptively routed to this object
 
 	// Keyboard Focus
 	LLUICtrl*			mKeyboardFocus;				// Keyboard events are preemptively routed to this object
+	LLUICtrl*			mLastKeyboardFocus;			// who last had focus
 	LLUICtrl*			mDefaultKeyboardFocus;
-	FocusLostCallback	mKeyboardFocusLostCallback;	// The object to which keyboard events are routed is called before another object takes its place
 
 	// Top View
 	LLUICtrl*			mTopCtrl;
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 1e49210565e0834893127eb6be621444707af94c..a063ebcd259357475f69a57af9ee2a889595f2b7 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -88,18 +88,11 @@ void LLIconCtrl::draw()
 {
 	if( getVisible() ) 
 	{
-		// Border
-		BOOL has_image = !mImageID.isNull();
-
-		if( has_image )
+		if( mImagep.notNull() )
 		{
-			if( mImagep.notNull() )
-			{
-				gl_draw_scaled_image(0, 0, 
-									 mRect.getWidth(), mRect.getHeight(), 
-									 mImagep,
-									 mColor );
-			}
+			mImagep->draw(0, 0, 
+							mRect.getWidth(), mRect.getHeight(), 
+							mColor );
 		}
 
 		LLUICtrl::draw();
@@ -154,6 +147,7 @@ LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *
 	LLUICtrlFactory::getAttributeColor(node,"color", color);
 
 	LLIconCtrl* icon = new LLIconCtrl(name, rect, image_id);
+
 	icon->setColor(color);
 
 	icon->initFromXML(node, parent);
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index b7892695580c6ed1b3d77b2016f9e9230b56fd8c..1e474d09350635a7d440a0387322ef824423263c 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -73,7 +73,7 @@ class LLIconCtrl
 	LLColor4		mColor;
 	LLString		mImageName;
 	LLUUID			mImageID;
-	LLPointer<LLImageGL>	mImagep;
+	LLPointer<LLUIImage>	mImagep;
 };
 
 #endif
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 3c7cd17b925fb545958d57669539ce46aadb0809..4297f5fef8592635cca0d844a954f1a92b03b246 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -128,7 +128,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
 						   S32 max_length_bytes,
 						   void (*commit_callback)(LLUICtrl* caller, void* user_data ),
 						   void (*keystroke_callback)(LLLineEditor* caller, void* user_data ),
-						   void (*focus_lost_callback)(LLUICtrl* caller, void* user_data ),
+						   void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data ),
 						   void* userdata,
 						   LLLinePrevalidateFunc prevalidate_func,
 						   LLViewBorder::EBevel border_bevel,
@@ -351,10 +351,14 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
 
 	// Check to see if entire field is selected.
 	S32 len = mText.length();
-	BOOL allSelected = (len > 0) && (( mSelectionStart == 0 && mSelectionEnd == len ) 
-		|| ( mSelectionStart == len && mSelectionEnd == 0 ));
+	BOOL all_selected = (len > 0)
+		&& (( mSelectionStart == 0 && mSelectionEnd == len ) 
+			|| ( mSelectionStart == len && mSelectionEnd == 0 ));
 
 	// Do safe truncation so we don't split multi-byte characters
+	// also consider entire string selected when mSelectAllonFocusReceived is set on an empty, focused line editor
+	all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
+
 	LLString truncated_utf8 = new_text;
 	if (truncated_utf8.size() > (U32)mMaxLengthBytes)
 	{	
@@ -362,7 +366,7 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
 	}
 	mText.assign(truncated_utf8);
 
-	if (allSelected)
+	if (all_selected)
 	{
 		// ...keep whole thing selected
 		selectAll();
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index a019353856ae3afb037ab8ea79187d8192e27cff..0739315c4d6b21c22e3a61d445fd8d696e94266c 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -77,7 +77,7 @@ class LLLineEditor
 				 S32 max_length_bytes = 254,
 				 void (*commit_callback)(LLUICtrl* caller, void* user_data) = NULL,
 				 void (*keystroke_callback)(LLLineEditor* caller, void* user_data) = NULL,
-				 void (*focus_lost_callback)(LLUICtrl* caller, void* user_data) = NULL,
+				 void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data) = NULL,
 				 void* userdata = NULL,
 				 LLLinePrevalidateFunc prevalidate_func = NULL,
 				 LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 46f9f515d7176e2dd59456c6fa968b65ceab738a..19a5085a2592efa819c44c502dbda9f843a2ad0a 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -4514,7 +4514,7 @@ BOOL LLMenuHolderGL::hideMenus()
 	}
 	//if (gFocusMgr.childHasKeyboardFocus(this))
 	//{
-	//	gFocusMgr.setKeyboardFocus(NULL, NULL);
+	//	gFocusMgr.setKeyboardFocus(NULL);
 	//}
 
 	return menu_visible;
@@ -4599,6 +4599,7 @@ void LLTearOffMenu::onFocusReceived()
 			break;
 		}
 	}
+	LLFloater::onFocusReceived();
 }
 
 void LLTearOffMenu::onFocusLost()
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index b8b8bf9443b5bd2d1d9b7fafc894ee9cd9123aa0..ca8020fe709465683cf8b7488f544ae38539be90 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -287,7 +287,7 @@ void LLModalDialog::onAppFocusLost()
 
 		if( gFocusMgr.childHasKeyboardFocus( instance ) )
 		{
-			gFocusMgr.setKeyboardFocus( NULL, NULL );
+			gFocusMgr.setKeyboardFocus( NULL );
 		}
 	}
 }
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 6d000f3e7ff0e45a418c5a9c6e935b0ba1572c73..294ce5df18173c7b389fa9902a71f61d3f943fa7 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -64,7 +64,6 @@ LLPanel::panel_map_t LLPanel::sPanelMap;
 LLPanel::alert_queue_t LLPanel::sAlertQueue;
 
 const S32 RESIZE_BAR_OVERLAP = 1;
-const S32 PANEL_STACK_GAP = RESIZE_BAR_HEIGHT;
 
 void LLPanel::init()
 {
@@ -88,6 +87,7 @@ LLPanel::LLPanel()
 : mRectControl()
 {
 	init();
+	setName("panel");
 }
 
 LLPanel::LLPanel(const LLString& name)
@@ -124,6 +124,7 @@ LLPanel::LLPanel(const LLString& name, const LLString& rect_control, BOOL border
 void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
 						LLViewBorder::EStyle border_style, S32 border_thickness)
 {
+	removeBorder();
 	mBorder = new LLViewBorder( "panel border", 
 								LLRect(0, mRect.getHeight(), mRect.getWidth(), 0), 
 								border_bevel, border_style, border_thickness );
@@ -361,12 +362,6 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 {
 	BOOL handled = FALSE;
 
-	if( getVisible() && getEnabled() && gFocusMgr.childHasKeyboardFocus(this) && KEY_ESCAPE == key )
-	{
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
-		return TRUE;
-	}
-
 	if( getVisible() && getEnabled() && 
 		gFocusMgr.childHasKeyboardFocus(this) && !called_from_parent )
 	{
@@ -472,7 +467,7 @@ void LLPanel::setFocus(BOOL b)
 	{
 		if( this == gFocusMgr.getKeyboardFocus() )
 		{
-			gFocusMgr.setKeyboardFocus( NULL, NULL );
+			gFocusMgr.setKeyboardFocus( NULL );
 		}
 		else
 		{
@@ -595,7 +590,8 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
 	{
 		LLRect rect;
 		createRect(node, rect, parent, LLRect());
-		panelp = new LLPanel(name, rect);
+		// create a new panel without a border, by default
+		panelp = new LLPanel(name, rect, FALSE);
 		panelp->initPanelXML(node, parent, factory);
 		// preserve panel's width and height, but override the location
 		const LLRect& panelrect = panelp->getRect();
@@ -608,12 +604,13 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
 	{
 		panelp->initPanelXML(node, parent, factory);
 	}
+
 	return panelp;
 }
 
 BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
 {
-	LLString name("panel");
+	LLString name = getName();
 	node->getAttributeString("name", name);
 	setName(name);
 
@@ -628,13 +625,15 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
 
 	if (!xml_filename.empty())
 	{
-		// Preserve postion of embedded panel but allow panel to dictate width/height
-		LLRect rect(getRect());
 		didPost = factory->buildPanel(this, xml_filename, NULL);
-		S32 w = getRect().getWidth();
-		S32 h = getRect().getHeight();
-		rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
-		setRect(rect);
+
+		LLRect new_rect = getRect();
+		// override rectangle with embedding parameters as provided
+		createRect(node, new_rect, parent);
+		setOrigin(new_rect.mLeft, new_rect.mBottom);
+		reshape(new_rect.getWidth(), new_rect.getHeight());
+		// optionally override follows flags from including nodes
+		parseFollowsFlags(node);
 	}
 	else
 	{
@@ -678,7 +677,7 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
 	initFromXML(node, parent);
 
 	/////// Border attributes ///////
-	BOOL border = FALSE;
+	BOOL border = mBorder != NULL;
 	node->getAttributeBOOL("border", border);
 	if (border)
 	{
@@ -706,24 +705,24 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
 	}
 
 	/////// Background attributes ///////
-	BOOL background_visible = FALSE;
+	BOOL background_visible = mBgVisible;
 	node->getAttributeBOOL("background_visible", background_visible);
 	setBackgroundVisible(background_visible);
 	
-	BOOL background_opaque = FALSE;
+	BOOL background_opaque = mBgOpaque;
 	node->getAttributeBOOL("background_opaque", background_opaque);
 	setBackgroundOpaque(background_opaque);
 
 	LLColor4 color;
-	color = LLUI::sColorsGroup->getColor( "FocusBackgroundColor" );
+	color = mBgColorOpaque;
 	LLUICtrlFactory::getAttributeColor(node,"bg_opaque_color", color);
 	setBackgroundColor(color);
 
-	color = LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" );
+	color = mBgColorAlpha;
 	LLUICtrlFactory::getAttributeColor(node,"bg_alpha_color", color);
 	setTransparentColor(color);
 
-	LLString label;
+	LLString label = getLabel();
 	node->getAttributeString("label", label);
 	setLabel(label);
 }
@@ -853,12 +852,12 @@ BOOL LLPanel::childHasFocus(const LLString& id)
 }
 
 
-void LLPanel::childSetFocusChangedCallback(const LLString& id, void (*cb)(LLUICtrl*, void*))
+void LLPanel::childSetFocusChangedCallback(const LLString& id, void (*cb)(LLFocusableElement*, void*), void* user_data)
 {
 	LLUICtrl* child = (LLUICtrl*)getChildByName(id, true);
 	if (child)
 	{
-		child->setFocusChangedCallback(cb);
+		child->setFocusChangedCallback(cb, user_data);
 	}
 }
 
@@ -1165,11 +1164,12 @@ void LLPanel::storeRectControl()
 //
 struct LLLayoutStack::LLEmbeddedPanel
 {
-	LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize) : 
+	LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : 
 			mPanel(panelp), 
 			mMinWidth(min_width), 
 			mMinHeight(min_height),
 			mAutoResize(auto_resize),
+			mUserResize(user_resize),
 			mOrientation(orientation),
 			mVisibleAmt(1.f) // default to fully visible
 	{
@@ -1205,6 +1205,7 @@ struct LLLayoutStack::LLEmbeddedPanel
 	S32 mMinWidth;
 	S32 mMinHeight;
 	BOOL mAutoResize;
+	BOOL mUserResize;
 	LLResizeBar* mResizeBar;
 	eLayoutOrientation mOrientation;
 	F32 mVisibleAmt;
@@ -1213,7 +1214,8 @@ struct LLLayoutStack::LLEmbeddedPanel
 LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) : 
 		mOrientation(orientation),
 		mMinWidth(0),
-		mMinHeight(0)
+		mMinHeight(0),
+		mPanelSpacing(RESIZE_BAR_HEIGHT)
 {
 }
 
@@ -1226,24 +1228,26 @@ void LLLayoutStack::draw()
 {
 	updateLayout();
 	{
-		// clip if outside nominal bounds
-		LLLocalClipRect clip(getLocalRect(), mRect.getWidth() > mMinWidth || mRect.getHeight() > mMinHeight);
 		e_panel_list_t::iterator panel_it;
 		for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
 		{
+			// clip to layout rectangle, not bounding rectangle
 			LLRect clip_rect = (*panel_it)->mPanel->getRect();
 			// scale clipping rectangle by visible amount
 			if (mOrientation == HORIZONTAL)
 			{
-				clip_rect.mRight = clip_rect.mLeft + llround(clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
+				clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
 			}
 			else
 			{
-				clip_rect.mBottom = clip_rect.mTop - llround(clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
+				clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
 			}
-			LLLocalClipRect clip(clip_rect, (*panel_it)->mVisibleAmt < 1.f);
+
+			LLPanel* panelp = (*panel_it)->mPanel;
+
+			LLLocalClipRect clip(clip_rect);
 			// only force drawing invisible children if visible amount is non-zero
-			drawChild((*panel_it)->mPanel, 0, 0, (*panel_it)->mVisibleAmt > 0.f);
+			drawChild(panelp, 0, 0, !clip_rect.isNull());
 		}
 	}
 }
@@ -1258,17 +1262,13 @@ void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
 		delete embedded_panelp;
 	}
 
+	// need to update resizebars
+
 	calcMinExtents();
 
 	LLView::removeCtrl(ctrl);
 }
 
-void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLView::reshape(width, height, called_from_parent);
-	//updateLayout();
-}
-
 LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
 {
 	LLXMLNodePtr node = LLView::getXML();
@@ -1298,6 +1298,14 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
 
 	LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
 
+	node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
+	// don't allow negative spacing values
+	layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
+
+	LLString name("stack");
+	node->getAttributeString("name", name);
+
+	layout_stackp->setName(name);
 	layout_stackp->initFromXML(node, parent);
 
 	LLXMLNodePtr child;
@@ -1308,16 +1316,18 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
 			S32 min_width = 0;
 			S32 min_height = 0;
 			BOOL auto_resize = TRUE;
+			BOOL user_resize = TRUE;
 
 			child->getAttributeS32("min_width", min_width);
 			child->getAttributeS32("min_height", min_height);
 			child->getAttributeBOOL("auto_resize", auto_resize);
+			child->getAttributeBOOL("user_resize", user_resize);
 
 			LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
 			if (panelp)
 			{
 				panelp->setFollowsNone();
-				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize);
+				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
 			}
 		}
 	}
@@ -1335,11 +1345,36 @@ S32 LLLayoutStack::getMinHeight()
 	return mMinHeight;
 }
 
-void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index)
+S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
 {
-	LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize);
+	// if we are spanning our children (crude upward propagation of size)
+	// then don't enforce our size on our children
+	if (mOrientation == HORIZONTAL)
+	{
+		cur_height = llmax(mMinHeight, mRect.getHeight());
+	}
+
+	return cur_height;
+}
+
+S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
+{
+	// if we are spanning our children (crude upward propagation of size)
+	// then don't enforce our size on our children
+	if (mOrientation == VERTICAL)
+	{
+		cur_width = llmax(mMinWidth, mRect.getWidth());
+	}
+
+	return cur_width;
+}
+
+void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index)
+{
+	LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
 	
 	mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
+	
 	addChild(panel);
 	addChild(embedded_panel->mResizeBar);
 
@@ -1347,29 +1382,15 @@ void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL
 	// with a bit of overlap
 	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
 	{
-		e_panel_list_t::iterator next_it = panel_it;
-		++next_it;
-
 		LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
 		sendChildToFront(resize_barp);
-		// last resize bar is disabled, since its not between any two panels
-		if ( next_it == mPanels.end() )
-		{
-			resize_barp->setEnabled(FALSE);
-		}
-		else
-		{
-			resize_barp->setEnabled(TRUE);
-		}
 	}
 
-	//updateLayout();
 }
 
 void LLLayoutStack::removePanel(LLPanel* panel)
 {
 	removeChild(panel);
-	//updateLayout();
 }
 
 void LLLayoutStack::updateLayout(BOOL force_resize)
@@ -1377,11 +1398,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 	calcMinExtents();
 
 	// calculate current extents
-	S32 cur_width = 0;
-	S32 cur_height = 0;
+	S32 total_width = 0;
+	S32 total_height = 0;
 
 	const F32 ANIM_OPEN_TIME = 0.02f;
-	const F32 ANIM_CLOSE_TIME = 0.02f;
+	const F32 ANIM_CLOSE_TIME = 0.03f;
 
 	e_panel_list_t::iterator panel_it;
 	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)
@@ -1403,23 +1424,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 				(*panel_it)->mVisibleAmt = 0.f;
 			}
 		}
+
 		if (mOrientation == HORIZONTAL)
 		{
- 			// all panels get expanded to max of all the minimum dimensions
-			cur_height = llmax(mMinHeight, panelp->getRect().getHeight());
-        	cur_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
-			if (panel_it != mPanels.end())
+        	total_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
+        	// want n-1 panel gaps for n panels
+			if (panel_it != mPanels.begin())
 			{
-				cur_width += PANEL_STACK_GAP;
+				total_width += mPanelSpacing;
 			}
 		}
 		else //VERTICAL
 		{
-            cur_width = llmax(mMinWidth, panelp->getRect().getWidth());
-			cur_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
-			if (panel_it != mPanels.end())
+			total_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
+			if (panel_it != mPanels.begin())
 			{
-				cur_height += PANEL_STACK_GAP;
+				total_height += mPanelSpacing;
 			}
 		}
 	}
@@ -1465,11 +1485,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 	S32 pixels_to_distribute;
 	if (mOrientation == HORIZONTAL)
 	{
-		pixels_to_distribute = mRect.getWidth() - cur_width;
+		pixels_to_distribute = mRect.getWidth() - total_width;
 	}
 	else //VERTICAL
 	{
-		pixels_to_distribute = mRect.getHeight() - cur_height;
+		pixels_to_distribute = mRect.getHeight() - total_height;
 	}
 
 	S32 cur_x = 0;
@@ -1482,7 +1502,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 		S32 cur_width = panelp->getRect().getWidth();
 		S32 cur_height = panelp->getRect().getHeight();
 		S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
-		S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
+		S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); 
 
 		S32 delta_size = 0;
 
@@ -1502,11 +1522,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 					// grow all elements equally
 					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
 				}
-				new_width = llmax((*panel_it)->mMinWidth, panelp->getRect().getWidth() + delta_size);
+				new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
 			}
 			else
 			{
-				new_width = llmax(mMinWidth, mRect.getWidth());
+				new_width = getDefaultWidth(new_width);
 			}
 
 			if (mOrientation == VERTICAL)
@@ -1520,22 +1540,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 				{
 					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
 				}
-				new_height = llmax((*panel_it)->mMinHeight, panelp->getRect().getHeight() + delta_size);
+				new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
 			}
 			else
 			{
-				new_height = llmax(mMinHeight, mRect.getHeight());
+				new_height = getDefaultHeight(new_height);
 			}
 		}
-		else // don't resize
+		else
 		{
 			if (mOrientation == HORIZONTAL)
 			{
-				new_height = llmax(mMinHeight, mRect.getHeight());
+				new_height = getDefaultHeight(new_height);
 			}
 			else // VERTICAL
 			{
-				new_width = llmax(mMinWidth, mRect.getWidth());
+				new_width = getDefaultWidth(new_width);
 			}
 		}
 
@@ -1550,22 +1570,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 		if (mOrientation == HORIZONTAL)
 		{
 			resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
-			resize_bar_rect.mRight = panel_rect.mRight + PANEL_STACK_GAP + RESIZE_BAR_OVERLAP;
+			resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
 		}
 		else
 		{
 			resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
-			resize_bar_rect.mBottom = panel_rect.mBottom - PANEL_STACK_GAP - RESIZE_BAR_OVERLAP;
+			resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
 		}
 		(*panel_it)->mResizeBar->setRect(resize_bar_rect);
 
 		if (mOrientation == HORIZONTAL)
 		{
-			cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
+			cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + mPanelSpacing;
 		}
 		else //VERTICAL
 		{
-			cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
+			cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + mPanelSpacing;
 		}
 	}
 
@@ -1577,29 +1597,38 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 
 		if (mOrientation == HORIZONTAL)
 		{
-			(*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinWidth, (*panel_it)->mMinWidth + shrink_headroom_total);
+			(*panel_it)->mResizeBar->setResizeLimits(
+				(*panel_it)->mMinWidth, 
+				(*panel_it)->mMinWidth + shrink_headroom_total);
 		}
 		else //VERTICAL
 		{
-			(*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinHeight, (*panel_it)->mMinHeight + shrink_headroom_total);
+			(*panel_it)->mResizeBar->setResizeLimits(
+				(*panel_it)->mMinHeight, 
+				(*panel_it)->mMinHeight + shrink_headroom_total);
 		}
-		// hide resize bars for invisible panels
-		(*panel_it)->mResizeBar->setVisible(panelp->getVisible());
-		if (panelp->getVisible())
+
+		// toggle resize bars based on panel visibility, resizability, etc
+		BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
+		(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
+
+		if (resize_bar_enabled)
 		{
 			last_resize_bar = (*panel_it)->mResizeBar;
 		}
 	}
 
 	// hide last resize bar as there is nothing past it
+	// resize bars need to be in between two resizable panels
 	if (last_resize_bar)
 	{
 		last_resize_bar->setVisible(FALSE);
 	}
 
 	// not enough room to fit existing contents
-	if (!force_resize && 
-		((cur_y != -PANEL_STACK_GAP) || (cur_x != mRect.getWidth() + PANEL_STACK_GAP)))
+	if (!force_resize 
+		&& ((cur_y != -mPanelSpacing) 
+			|| (cur_x != mRect.getWidth() + mPanelSpacing)))
 	{
 		// do another layout pass with all stacked elements contributing
 		// even those that don't usually resize
@@ -1631,20 +1660,22 @@ void LLLayoutStack::calcMinExtents()
 	{
 		if (mOrientation == HORIZONTAL)
 		{
-			mMinHeight = llmax(mMinHeight, (*panel_it)->mMinHeight);
+			mMinHeight = llmax(	mMinHeight, 
+								(*panel_it)->mMinHeight);
             mMinWidth += (*panel_it)->mMinWidth;
 			if (panel_it != mPanels.begin())
 			{
-				mMinWidth += PANEL_STACK_GAP;
+				mMinWidth += mPanelSpacing;
 			}
 		}
 		else //VERTICAL
 		{
-            mMinWidth = llmax(mMinWidth, (*panel_it)->mMinWidth);
+	        mMinWidth = llmax(	mMinWidth, 
+								(*panel_it)->mMinWidth);
 			mMinHeight += (*panel_it)->mMinHeight;
 			if (panel_it != mPanels.begin())
 			{
-				mMinHeight += PANEL_STACK_GAP;
+				mMinHeight += mPanelSpacing;
 			}
 		}
 	}
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 78aa7cfc216ae38cfacceab47ff2ca68d553a8e4..88b4ecb76b8c53e6535fe6d7664edf81c4c3d019 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -173,7 +173,7 @@ class LLPanel : public LLUICtrl
 	// LLUICtrl
 	void childSetFocus(const LLString& id, BOOL focus = TRUE);
 	BOOL childHasFocus(const LLString& id);
-	void childSetFocusChangedCallback(const LLString& id, void (*cb)(LLUICtrl*, void*));
+	void childSetFocusChangedCallback(const LLString& id, void (*cb)(LLFocusableElement*, void*), void* user_data = NULL);
 	
 	void childSetCommitCallback(const LLString& id, void (*cb)(LLUICtrl*, void*), void* userdata = NULL );
 	void childSetDoubleClickCallback(const LLString& id, void (*cb)(void*), void* userdata = NULL );
@@ -277,9 +277,9 @@ class LLLayoutStack : public LLView
 	virtual ~LLLayoutStack();
 
 	/*virtual*/ void draw();
-	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 	/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
 	/*virtual*/ void removeCtrl(LLUICtrl* ctrl);
+
 	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LAYOUT_STACK; }
 	virtual LLString getWidgetTag() const { return LL_LAYOUT_STACK_TAG; }
 
@@ -288,7 +288,7 @@ class LLLayoutStack : public LLView
 	S32 getMinWidth();
 	S32 getMinHeight();
 	
-	void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index = S32_MAX);
+	void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index = S32_MAX);
 	void removePanel(LLPanel* panel);
 	void updateLayout(BOOL force_resize = FALSE);
 
@@ -299,6 +299,8 @@ class LLLayoutStack : public LLView
 	void calcMinExtents();
 	S32 getMinStackSize();
 	S32 getCurStackSize();
+	S32 getDefaultHeight(S32 cur_height);
+	S32 getDefaultWidth(S32 cur_width);
 
 protected:
 	eLayoutOrientation mOrientation;
@@ -308,6 +310,7 @@ class LLLayoutStack : public LLView
 
 	S32 mMinWidth;
 	S32 mMinHeight;
+	S32 mPanelSpacing;
 };
 
 #endif
diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp
index 17b76def7127e2ab35dc3f3d32a9d4fb4005d3df..120323e7d1d75e3a0034b0c39fd8f3973cdc0647 100644
--- a/indra/llui/llresizehandle.cpp
+++ b/indra/llui/llresizehandle.cpp
@@ -60,7 +60,7 @@ LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 mi
 	if( RIGHT_BOTTOM == mCorner)
 	{
 		LLUUID image_id(LLUI::sConfigGroup->getString("UIImgResizeBottomRightUUID"));
-		mImage = LLUI::sImageProvider->getUIImageByID(image_id);
+		mImage = LLUI::sImageProvider->getImageByID(image_id);
 	}
 
 	switch( mCorner )
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 99908a6bc0248b111ed28d7c92824b3238cb445b..b106bb570d69a502a3cef1eb10c6b29ce06c9d82 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -159,30 +159,50 @@ void LLScrollbar::setDocParams( S32 size, S32 pos )
 
 void LLScrollbar::setDocPos(S32 pos)
 {
-	mDocPos = llclamp( pos, 0, getDocPosMax() );
-	mDocChanged = TRUE;
+	if (pos != mDocPos)
+	{
+		mDocPos = llclamp( pos, 0, getDocPosMax() );
+		mDocChanged = TRUE;
 
-	updateThumbRect();
+		updateThumbRect();
+	}
 }
 
 void LLScrollbar::setDocSize(S32 size)
 {
-	mDocSize = size;
-	mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
-	mDocChanged = TRUE;
+	if (size != mDocSize)
+	{
+		mDocSize = size;
+		mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
+		mDocChanged = TRUE;
 
-	updateThumbRect();
+		updateThumbRect();
+	}
 }
 
 void LLScrollbar::setPageSize( S32 page_size )
 {
-	mPageSize = page_size;
-	mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
-	mDocChanged = TRUE;
+	if (page_size != mPageSize)
+	{
+		mPageSize = page_size;
+		mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
+		mDocChanged = TRUE;
 
-	updateThumbRect();
+		updateThumbRect();
+	}
+}
+
+BOOL LLScrollbar::isAtBeginning()
+{
+	return mDocPos == 0;
+}
+
+BOOL LLScrollbar::isAtEnd()
+{
+	return mDocPos == getDocPosMax();
 }
 
+
 void LLScrollbar::updateThumbRect()
 {
 //	llassert( 0 <= mDocSize );
@@ -479,7 +499,7 @@ void LLScrollbar::draw()
 		// Draw background and thumb.
 		LLUUID rounded_rect_image_id;
 		rounded_rect_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
-		LLImageGL* rounded_rect_imagep = LLUI::sImageProvider->getUIImageByID(rounded_rect_image_id);
+		LLImageGL* rounded_rect_imagep = LLUI::sImageProvider->getImageByID(rounded_rect_image_id);
 
 		if (!rounded_rect_imagep)
 		{
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index 353935cfb874637e228e20442ea9cfad35adb852..50aa3cafe934fc38e8026705f046d4dd513362fb 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -88,6 +88,9 @@ class LLScrollbar
 	void				setDocPos( S32 pos );
 	S32					getDocPos()				{ return mDocPos; }
 
+	BOOL				isAtBeginning();
+	BOOL				isAtEnd();
+
 	// How many "lines" of the "document" is can appear on a page.
 	void				setPageSize( S32 page_size );
 	S32					getPageSize()			{ return mPageSize; }
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 8b5d009b95dd09f84459f1e43ed2639c4b940912..34a29cef517c9c7dd7b20019e80a63d820542296 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -394,33 +394,29 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
 
 BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect)
 {
-	if( getVisible() && pointInView(x,y) )
+	S32 local_x, local_y;
+	for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
 	{
-		S32 local_x, local_y;
-		for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
+		local_x = x - mScrollbar[i]->getRect().mLeft;
+		local_y = y - mScrollbar[i]->getRect().mBottom;
+		if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
 		{
-			local_x = x - mScrollbar[i]->getRect().mLeft;
-			local_y = y - mScrollbar[i]->getRect().mBottom;
-			if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
-		// Handle 'child' view.
-		if( mScrolledView )
+	}
+	// Handle 'child' view.
+	if( mScrolledView )
+	{
+		local_x = x - mScrolledView->getRect().mLeft;
+		local_y = y - mScrolledView->getRect().mBottom;
+		if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
 		{
-			local_x = x - mScrolledView->getRect().mLeft;
-			local_y = y - mScrolledView->getRect().mBottom;
-			if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
-
-		// Opaque
-		return TRUE;
 	}
-	return FALSE;
+
+	// Opaque
+	return TRUE;
 }
 
 void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar )
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 96a739418f945d95b192a540b31e1a308eeaaf53..0c81b2da0832952009c5fc2229760897045637a5 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -61,43 +61,55 @@ const S32 LIST_SNAP_PADDING = 5;
 // local structures & classes.
 struct SortScrollListItem
 {
-	SortScrollListItem(const S32 sort_col, BOOL sort_ascending)
-	{
-		mSortCol = sort_col;
-		mSortAscending = sort_ascending;
-	}
+	SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders)
+	:	mSortOrders(sort_orders)
+	{}
 
 	bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
 	{
-		const LLScrollListCell *cell1;
-		const LLScrollListCell *cell2;
-		
-		cell1 = i1->getColumn(mSortCol);
-		cell2 = i2->getColumn(mSortCol);
+		if ( mSortOrders.empty() ) return true;
+
+		const LLScrollListCell *cell1 = NULL;
+		const LLScrollListCell *cell2 = NULL;
 		
-		S32 order = 1;
-		if (!mSortAscending)
+		sort_order_t::const_reverse_iterator end_it = mSortOrders.rend();
+		sort_order_t::const_reverse_iterator it;
+
+		// sort over all columns in order specified by mSortOrders
+		S32 sort_result = 0;
+		for (it = mSortOrders.rbegin(); it != end_it; ++it)
 		{
-			order = -1;
-		}
+			S32 col_idx = it->first;
+			BOOL sort_ascending = it->second;
 
-		BOOL retval = FALSE;
+			cell1 = i1->getColumn(col_idx);
+			cell2 = i2->getColumn(col_idx);
+			// ascending or descending sort for this column?
+			S32 order = 1;
+			if (!sort_ascending)
+			{
+				order = -1;
+			}
 
-		if (cell1 && cell2)
-		{
-			retval = ((order * LLString::compareDict(cell1->getText(),	cell2->getText())) < 0);
+			if (cell1 && cell2)
+			{
+				sort_result = (order * LLString::compareDict(cell1->getValue().asString(), cell2->getValue().asString()));
+				if (sort_result != 0)
+				{
+					// we have a sort order!
+					break;
+				}
+			}
 		}
 
-		return (retval ? TRUE : FALSE);
+		return sort_result < 0;
 	}
 
-protected:
-	S32 mSortCol;
-	S32 mSortAscending;
+	typedef std::vector<std::pair<S32, BOOL> > sort_order_t;
+	const sort_order_t& mSortOrders;
 };
 
 
-
 //
 // LLScrollListIcon
 //
@@ -120,6 +132,14 @@ LLScrollListIcon::~LLScrollListIcon()
 {
 }
 
+void LLScrollListIcon::setValue(LLSD value)
+{
+	mImageUUID = value.asUUID();
+	// don't use default image specified by LLUUID::null, use no image in that case
+	mIcon = mImageUUID.isNull() ? NULL : LLUI::sImageProvider->getImageByID(value.asUUID());
+}
+
+
 void LLScrollListIcon::setColor(const LLColor4& color)
 {
 	mColor = color;
@@ -127,7 +147,10 @@ void LLScrollListIcon::setColor(const LLColor4& color)
 
 void LLScrollListIcon::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const	
 {
-	gl_draw_image(0, 0, mIcon, mColor); 
+	if (mIcon)
+	{
+		gl_draw_image(0, 0, mIcon, mColor); 
+	}
 }
 
 //
@@ -158,15 +181,15 @@ LLScrollListCheck::~LLScrollListCheck()
 void LLScrollListCheck::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
 {
 	mCheckBox->draw();
-
 }
 
 BOOL LLScrollListCheck::handleClick()
 { 
-	if ( mCheckBox->getEnabled() )
+	if (mCheckBox->getEnabled())
 	{
-		LLCheckBoxCtrl::onButtonPress(mCheckBox); 
+		mCheckBox->toggle();
 	}
+	// don't change selection when clicking on embedded checkbox
 	return TRUE; 
 }
 
@@ -213,7 +236,7 @@ LLScrollListText::LLScrollListText( const LLString& text, const LLFontGL* font,
 	// initialize rounded rect image
 	if (!mRoundedRectImage)
 	{
-		mRoundedRectImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("rounded_square.tga")));
+		mRoundedRectImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("rounded_square.tga")));
 	}
 }
 
@@ -223,6 +246,12 @@ LLScrollListText::~LLScrollListText()
 	delete mColor;
 }
 
+S32	LLScrollListText::getContentWidth() const
+{
+	return mFont->getWidth(mText.getString());
+}
+
+
 void LLScrollListText::setColor(const LLColor4& color)
 {
 	if (!mColor)
@@ -314,31 +343,6 @@ LLScrollListItem::~LLScrollListItem()
 	std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
 }
 
-BOOL LLScrollListItem::handleClick(S32 x, S32 y, MASK mask)
-{
-	BOOL handled = FALSE;
-
-	S32 left = 0;
-	S32 right = 0;
-	S32 width = 0;
-
-	std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
-	std::vector<LLScrollListCell *>::iterator end = mColumns.end();
-	for ( ; iter != end; ++iter)
-	{
-		width = (*iter)->getWidth();
-		right += width;
-		if (left <= x && x < right )
-		{
-			handled = (*iter)->handleClick();
-			break;
-		}
-		
-		left += width;
-	}
-	return handled;
-}
-
 void LLScrollListItem::setNumColumns(S32 columns)
 {
 	S32 prev_columns = mColumns.size();
@@ -375,7 +379,7 @@ LLString LLScrollListItem::getContentsCSV()
 	S32 count = getNumColumns();
 	for (S32 i=0; i<count; ++i)
 	{
-		ret += getColumn(i)->getText();
+		ret += getColumn(i)->getValue().asString();
 		if (i < count-1)
 		{
 			ret += ", ";
@@ -387,16 +391,7 @@ LLString LLScrollListItem::getContentsCSV()
 
 void LLScrollListItem::setEnabled(BOOL b)
 {
-	if (b != mEnabled)
-	{
-		std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
-		std::vector<LLScrollListCell *>::iterator end = mColumns.end();
-		for ( ; iter != end; ++iter)
-		{
-			(*iter)->setEnabled(b);
-		}
-		mEnabled = b;
-	}
+	mEnabled = b;
 }
 
 //---------------------------------------------------------------------------
@@ -424,9 +419,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
 	mCanSelect(TRUE),
 	mDisplayColumnHeaders(FALSE),
 	mCollapseEmptyColumns(FALSE),
-	mIsPopup(FALSE),
 	mMaxItemCount(INT_MAX), 
-	//mItemCount(0),
+	mMaxContentWidth(0),
 	mBackgroundVisible( TRUE ),
 	mDrawStripes(TRUE),
 	mBgWriteableColor(	LLUI::sColorsGroup->getColor( "ScrollBgWriteableColor" ) ),
@@ -443,12 +437,13 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
 	mOnSortChangedCallback( NULL ),
 	mHighlightedItem(-1),
 	mBorder(NULL),
-	mDefaultColumn("SIMPLE"),
+	mDefaultColumnName("SIMPLE"),
 	mSearchColumn(0),
 	mNumDynamicWidthColumns(0),
 	mTotalStaticColumnWidth(0),
-	mSortColumn(-1),
 	mSortAscending(TRUE),
+	mSecondarySortColumn(-1),
+	mSecondarySortAscending(TRUE),
 	mSorted(TRUE),
 	mDirty(FALSE),
 	mOriginalSelection(-1),
@@ -457,7 +452,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
 	mItemListRect.setOriginAndSize(
 		mBorderThickness + LIST_BORDER_PAD,
 		mBorderThickness + LIST_BORDER_PAD,
-		mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
+		mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ),
 		mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) );
 
 	updateLineHeight();
@@ -481,7 +476,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
 	mScrollbar->setFollowsTop();
 	mScrollbar->setFollowsBottom();
 	mScrollbar->setEnabled( TRUE );
-	mScrollbar->setVisible( TRUE );
+	// scrollbar is visible only when needed
+	mScrollbar->setVisible(FALSE);
 	addChild(mScrollbar);
 
 	// Border
@@ -539,7 +535,8 @@ void LLScrollListCtrl::clearRows()
 
 	mScrollLines = 0;
 	mLastSelected = NULL;
-	updateMaxContentWidth(NULL);
+	calcMaxContentWidth(NULL);
+	updateLayout();
 	mDirty = FALSE; 
 }
 
@@ -620,38 +617,64 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const
 	return ret;
 }
 
+// returns first matching item
+LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const
+{
+	LLString string_val = sd.asString();
+
+	item_list::const_iterator iter;
+	for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
+	{
+		LLScrollListItem* item  = *iter;
+		// assumes string representation is good enough for comparison
+		if (item->getValue().asString() == string_val)
+		{
+			return item;
+		}
+	}
+	return NULL;
+}
+
 
 void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
 {
-	S32 old_height = mRect.getHeight();
 	LLUICtrl::reshape( width, height, called_from_parent );
 
-	S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
+	updateLayout();
+}
 
+void LLScrollListCtrl::updateLayout()
+{
+	// reserve room for column headers, if needed
+	S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
 	mItemListRect.setOriginAndSize(
 		mBorderThickness + LIST_BORDER_PAD,
 		mBorderThickness + LIST_BORDER_PAD,
-		mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
+		mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ),
 		mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) - heading_size );
 
+	// how many lines of content in a single "page"
 	mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0;
-	if(old_height < height && getScrollPos() == mScrollbar->getDocPosMax())
+	BOOL scrollbar_visible = getItemCount() > mPageLines;
+	if (scrollbar_visible)
 	{
-		setScrollPos(mScrollbar->getDocPosMax());
+		// provide space on the right for scrollbar
+		mItemListRect.mRight = mRect.getWidth() - ( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE;
 	}
-	mScrollbar->setVisible(mPageLines < getItemCount());
+
+	mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
 	mScrollbar->setPageSize( mPageLines );
-		
+	mScrollbar->setDocSize( getItemCount() );
+	mScrollbar->setVisible(scrollbar_visible);
+
 	updateColumns();
 }
 
 // Attempt to size the control to show all items.
 // Do not make larger than width or height.
-void LLScrollListCtrl::arrange(S32 max_width, S32 max_height)
+void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height)
 {
-	S32 height = mLineHeight * (getItemCount() + 1);
-	height = llmin( height, max_height );
-
+	S32 height = llmin( getRequiredRect().getHeight(), max_height );
 	S32 width = mRect.getWidth();
 
 	reshape( width, height );
@@ -660,7 +683,10 @@ void LLScrollListCtrl::arrange(S32 max_width, S32 max_height)
 
 LLRect LLScrollListCtrl::getRequiredRect()
 {
-	S32 height = mLineHeight * (getItemCount() + 1);
+	S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
+	S32 height = (mLineHeight * getItemCount()) 
+				+ (2 * ( mBorderThickness + LIST_BORDER_PAD )) 
+				+ heading_size;
 	S32 width = mRect.getWidth();
 
 	return LLRect(0, height, width, 0);
@@ -680,15 +706,22 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
 			break;
 	
 		case ADD_SORTED:
-			if (mSortColumn == -1)
 			{
-				mSortColumn = 0;
-				mSortAscending = TRUE;
-			}
-			mItemList.push_back(item);
-			std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
-			break;
-	
+				// sort by column 0, in ascending order
+				std::vector<sort_column_t> single_sort_column;
+				single_sort_column.push_back(std::make_pair(0, TRUE));
+
+				mItemList.push_back(item);
+				std::stable_sort(
+					mItemList.begin(), 
+					mItemList.end(), 
+					SortScrollListItem(single_sort_column));
+				
+				// ADD_SORTED just sorts by first column...
+				// this might not match user sort criteria, so flag list as being in unsorted state
+				setSorted(FALSE);
+				break;
+			}	
 		case ADD_BOTTOM:
 			mItemList.push_back(item);
 			setSorted(FALSE);
@@ -702,33 +735,31 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
 		}
 	
 		updateLineHeightInsert(item);
-		mPageLines = mLineHeight ? mItemListRect.getHeight() / mLineHeight : 0;
-		BOOL scrollbar_visible = mPageLines < getItemCount();
-		
-		if (scrollbar_visible != mScrollbar->getVisible())
-		{
-			mScrollbar->setVisible(mPageLines < getItemCount());
-			updateColumns();
-		}
-		mScrollbar->setPageSize( mPageLines );
-	
-		mScrollbar->setDocSize( getItemCount() );
+		calcMaxContentWidth(item);
 
-		updateMaxContentWidth(item);
+		updateLayout();
 	}
 
 	return not_too_big;
 }
 
-void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
+void LLScrollListCtrl::calcMaxContentWidth(LLScrollListItem* added_item)
 {
 	const S32 HEADING_TEXT_PADDING = 30;
 	const S32 COLUMN_TEXT_PADDING = 20;
 
-	std::map<LLString, LLScrollListColumn>::iterator column_itor;
-	for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
+	if (added_item == NULL)
+	{
+		mMaxContentWidth = 0;
+	}
+
+	S32 item_content_width = 0;
+
+	ordered_columns_t::iterator column_itor;
+	for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor)
 	{
-		LLScrollListColumn* column = &column_itor->second;
+		LLScrollListColumn* column = *column_itor;
+		if (!column) continue;
 
 		if (!added_item)
 		{
@@ -740,7 +771,7 @@ void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
 				LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
 				if (!cellp) continue;
 
-				column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+				column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
 			}
 		}
 		else
@@ -748,9 +779,13 @@ void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
 			LLScrollListCell* cellp = added_item->getColumn(column->mIndex);
 			if (!cellp) continue;
 
-			column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+			column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
 		}
+
+		item_content_width += column->mMaxContentWidth;
 	}
+
+	mMaxContentWidth = llmax(mMaxContentWidth, item_content_width);
 }
 
 const S32 SCROLL_LIST_ROW_PAD = 2;
@@ -789,7 +824,6 @@ void LLScrollListCtrl::updateColumns()
 	mColumnsIndexed.resize(mColumns.size());
 
 	std::map<LLString, LLScrollListColumn>::iterator column_itor;
-	bool first_dynamic = true;
 	for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
 	{
 		LLScrollListColumn *column = &column_itor->second;
@@ -801,11 +835,6 @@ void LLScrollListCtrl::updateColumns()
 		else if (column->mDynamicWidth)
 		{
 			new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
-			if(first_dynamic)
-			{
-				first_dynamic = false;
-				new_width += (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
-			}
 		}
 
 		if (new_width != column->mWidth)
@@ -854,43 +883,38 @@ void LLScrollListCtrl::updateColumns()
 			}
 			right = llmax(left, llmin(mItemListRect.getWidth(), right));
 			S32 header_width = right - left;
-			
+
 			last_header->reshape(header_width, mHeadingHeight);
-			last_header->translate(left - last_header->getRect().mLeft, top - last_header->getRect().mBottom);
+			last_header->translate(
+				left - last_header->getRect().mLeft,
+				top - last_header->getRect().mBottom);
 			last_header->setVisible(mDisplayColumnHeaders && header_width > 0);
 			left = right;
 		}
 	}
 
 	// expand last column header we encountered to full list width
-
 	if (last_header)
 	{
-		S32 header_strip_width = mItemListRect.getWidth() + (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
-		S32 new_width = llmax(0, mItemListRect.mLeft + header_strip_width - last_header->getRect().mLeft);
+		S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
 		last_header->reshape(new_width, last_header->getRect().getHeight());
 		last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
 	}
-
 }
 
 void LLScrollListCtrl::setDisplayHeading(BOOL display)
 {
 	mDisplayColumnHeaders = display;
 
-	updateColumns();
-
-	setHeadingHeight(mHeadingHeight);
+	updateLayout();
 }
 
 void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
 {
 	mHeadingHeight = heading_height;
 
-	reshape(mRect.getWidth(), mRect.getHeight());
+	updateLayout();
 
-	// Resize
-	mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
 }
 
 void LLScrollListCtrl::setCollapseEmptyColumns(BOOL collapse)
@@ -934,6 +958,8 @@ BOOL LLScrollListCtrl::selectFirstItem()
 
 BOOL LLScrollListCtrl::selectNthItem( S32 target_index )
 {
+	if (mItemList.empty()) return FALSE;
+
 	// Deselects all other items
 	BOOL success = FALSE;
 	S32 index = 0;
@@ -1012,7 +1038,32 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index)
 	}
 	delete itemp;
 	mItemList.erase(mItemList.begin() + target_index);
-	updateMaxContentWidth(NULL);
+	calcMaxContentWidth(NULL);
+}
+
+//FIXME: refactor item deletion
+void LLScrollListCtrl::deleteItems(const LLSD& sd)
+{
+	item_list::iterator iter;
+	for (iter = mItemList.begin(); iter < mItemList.end(); )
+	{
+		LLScrollListItem* itemp = *iter;
+		if (itemp->getValue().asString() == sd.asString())
+		{
+			if (itemp == mLastSelected)
+			{
+				mLastSelected = NULL;
+			}
+			delete itemp;
+			mItemList.erase(iter++);
+		}
+		else
+		{
+			iter++;
+		}
+	}
+
+	calcMaxContentWidth(NULL);
 }
 
 void LLScrollListCtrl::deleteSelectedItems()
@@ -1032,7 +1083,7 @@ void LLScrollListCtrl::deleteSelectedItems()
 		}
 	}
 	mLastSelected = NULL;
-	updateMaxContentWidth(NULL);
+	calcMaxContentWidth(NULL);
 }
 
 void LLScrollListCtrl::highlightNthItem(S32 target_index)
@@ -1108,7 +1159,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
 
 	if (!getFirstSelected())
 	{
-		selectFirstItem();
+		// select last item
+		selectNthItem(getItemCount() - 1);
 	}
 	else
 	{
@@ -1130,7 +1182,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
 				break;
 			}
 
-			prev_item = cur_item;
+			// don't allow navigation to disabled elements
+			prev_item = cur_item->getEnabled() ? cur_item : prev_item;
 		}
 	}
 
@@ -1145,32 +1198,34 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
 
 void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
 {
+	LLScrollListItem* next_item = NULL;
+
 	if (!getFirstSelected())
 	{
 		selectFirstItem();
 	}
 	else
 	{
-		item_list::iterator iter;
-		for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+		item_list::reverse_iterator iter;
+		for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++)
 		{
-			LLScrollListItem* item = *iter;
-			if (item->getSelected())
+			LLScrollListItem* cur_item = *iter;
+
+			if (cur_item->getSelected())
 			{
-				if (++iter != mItemList.end())
+				if (next_item)
 				{
-					LLScrollListItem *next_item = *iter;
-					if (next_item)
-					{
-						selectItem(next_item, !extend_selection);
-					}
-					else
-					{
-						reportInvalidInput();
-					}
+					selectItem(next_item, !extend_selection);
+				}
+				else
+				{
+					reportInvalidInput();
 				}
 				break;
 			}
+
+			// don't allow navigation to disabled items
+			next_item = cur_item->getEnabled() ? cur_item : next_item;
 		}
 	}
 
@@ -1213,10 +1268,29 @@ LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, EAd
 		item->setEnabled(enabled);
 		item->addColumn( item_text, gResMgr->getRes( LLFONT_SANSSERIF_SMALL ) );
 		addItem( item, pos );
+
+		// create new column on demand for "simple" items
+		if (mColumns.empty())
+		{
+			LLSD new_column;
+			new_column["name"] = mDefaultColumnName;
+			new_column["label"] = "";
+			new_column["dynamicwidth"] = TRUE;
+			addColumn(new_column);
+		}
 	}
 	return item;
 }
 
+LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos)
+{
+	LLSD item;	
+	item["enabled"] = FALSE;
+	item["columns"][0]["type"] = "separator";
+	item["columns"][0]["column"] = mDefaultColumnName;
+
+	return addElement(item, pos);
+}
 
 // Selects first enabled item of the given name.
 // Returns false if item not found.
@@ -1242,7 +1316,7 @@ BOOL LLScrollListCtrl::selectSimpleItem(const LLString& label, BOOL case_sensiti
 	{
 		LLScrollListItem* item = *iter;
 		// Only select enabled items with matching names
-		LLString item_text = item->getColumn(0)->getText();
+		LLString item_text = item->getColumn(0)->getValue().asString();
 		if (!case_sensitive)
 		{
 			LLString::toLower(item_text);
@@ -1288,7 +1362,7 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
 			LLScrollListItem* item = *iter;
 			// Only select enabled items with matching names
 			LLScrollListCell* cellp = item->getColumn(mSearchColumn);
-			BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getText()[0]) : FALSE;
+			BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
 			if (select)
 			{
 				selectItem(item);
@@ -1315,7 +1389,7 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
 			{
 				continue;
 			}
-			LLWString item_label = utf8str_to_wstring(cellp->getText());
+			LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
 			if (!case_sensitive)
 			{
 				LLWString::toLower(item_label);
@@ -1346,14 +1420,14 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
 	return found;
 }
 
-const LLString& LLScrollListCtrl::getSimpleSelectedItem(S32 column) const
+const LLString LLScrollListCtrl::getSimpleSelectedItem(S32 column) const
 {
 	LLScrollListItem* item;
 
 	item = getFirstSelected();
 	if (item)
 	{
-		return item->getColumn(column)->getText();
+		return item->getColumn(column)->getValue().asString();
 	}
 
 	return LLString::null;
@@ -1384,6 +1458,16 @@ LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, LLS
 		item->setEnabled(enabled);
 		item->addColumn(item_text, gResMgr->getRes(LLFONT_SANSSERIF_SMALL), column_width);
 		addItem( item, pos );
+
+		// create new column on demand
+		if (mColumns.empty())
+		{
+			LLSD new_column;
+			new_column["name"] = "default_column";
+			new_column["label"] = "";
+			new_column["dynamicwidth"] = TRUE;
+			addColumn(new_column);
+		}
 	}
 	return item;
 }
@@ -1481,9 +1565,7 @@ void LLScrollListCtrl::drawItems()
 	LLGLSUIDefault gls_ui;
 	
 	{
-		LLRect clip_rect = mItemListRect;
-		if(!mScrollbar->getVisible()) clip_rect.mRight += SCROLLBAR_SIZE;
-		LLLocalClipRect clip(clip_rect);
+		LLLocalClipRect clip(mItemListRect);
 
 		S32 cur_x = x;
 		S32 cur_y = y;
@@ -1491,7 +1573,6 @@ void LLScrollListCtrl::drawItems()
 		mDrewSelected = FALSE;
 
 		S32 line = 0;
-		LLColor4 color;
 		S32 max_columns = 0;
 
 		item_list::iterator iter;
@@ -1502,7 +1583,7 @@ void LLScrollListCtrl::drawItems()
 			item_rect.setOriginAndSize( 
 				cur_x, 
 				cur_y, 
-				mScrollbar->getVisible() ? mItemListRect.getWidth() : mItemListRect.getWidth() + SCROLLBAR_SIZE,
+				mScrollbar->getVisible() ? mItemListRect.getWidth() : mItemListRect.getWidth() + mScrollbar->getRect().getWidth(),
 				mLineHeight );
 
 			//llinfos << item_rect.getWidth() << llendl;
@@ -1514,37 +1595,43 @@ void LLScrollListCtrl::drawItems()
 
 			max_columns = llmax(max_columns, item->getNumColumns());
 
+			LLColor4 fg_color;
 			LLRect bg_rect = item_rect;
 			// pad background rectangle to separate it from contents
 			bg_rect.stretch(LIST_BORDER_PAD, 0);
+			LLColor4 bg_color(0.f, 0.f, 0.f, 0.f);
 
 			if( mScrollLines <= line && line < mScrollLines + num_page_lines )
 			{
 				if( item->getSelected() && mCanSelect)
 				{
 					// Draw background of selected item
-					LLGLSNoTexture no_texture;
-					glColor4fv(mBgSelectedColor.mV);
-					gl_rect_2d( bg_rect );
-                    
-					color = mFgSelectedColor;
+					bg_color = mBgSelectedColor;
+					fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor);
 				}
 				else if (mHighlightedItem == line && mCanSelect)
 				{
-					LLGLSNoTexture no_texture;
-					glColor4fv(mHighlightedColor.mV);
-					gl_rect_2d( bg_rect );
-					color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+					bg_color = mHighlightedColor;
+					fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
 				}
 				else 
 				{
-					color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
 					if (mDrawStripes && (line%2 == 0) && (max_columns > 1))
 					{
-						LLGLSNoTexture no_texture;
-						glColor4fv(mBgStripeColor.mV);
-						gl_rect_2d( bg_rect );
+						bg_color = mBgStripeColor;
 					}
+					fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+				}
+
+				if (!item->getEnabled())
+				{
+					bg_color = mBgReadOnlyColor;
+				}
+				// draw background rect
+				{
+					LLGLSNoTexture no_texture;
+					glColor4fv(bg_color.mV);
+					gl_rect_2d( bg_rect );
 				}
 
 				S32 line_x = cur_x;
@@ -1553,7 +1640,6 @@ void LLScrollListCtrl::drawItems()
 					S32 cur_col = 0;
 					S32 dynamic_width = 0;
 					S32 dynamic_remainder = 0;
-					bool first_dynamic = true;
 					if(mNumDynamicWidthColumns > 0)
 					{
 						dynamic_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
@@ -1563,15 +1649,9 @@ void LLScrollListCtrl::drawItems()
 					for (LLScrollListCell* cell = item->getColumn(0); cur_col < num_cols; cell = item->getColumn(++cur_col))
 					{
 						S32 cell_width = cell->getWidth();
-						
 						if(mColumnsIndexed.size() > (U32)cur_col && mColumnsIndexed[cur_col] && mColumnsIndexed[cur_col]->mDynamicWidth)
 						{							
 							cell_width = dynamic_width + (--dynamic_remainder ? 1 : 0);
-							if(first_dynamic)
-							{
-								cell_width += mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE;
-								first_dynamic = false;
-							}
 							cell->setWidth(cell_width);
 						}
 						// Two ways a cell could be hidden
@@ -1585,7 +1665,7 @@ void LLScrollListCtrl::drawItems()
 						F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout");
 
 						highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f);
-						cell->drawToWidth( space_left, color, highlight_color );
+						cell->drawToWidth( space_left, fg_color, highlight_color );
 						LLUI::popMatrix();
 						
 						cur_x += cell_width + mColumnPadding;
@@ -1605,6 +1685,12 @@ void LLScrollListCtrl::draw()
 {
 	if( getVisible() )
 	{
+		// if user specifies sort, make sure it is maintained
+		if (needsSorting() && !isSorted())
+		{
+			sortItems();
+		}
+
 		if (mNeedsScroll)
 		{
 			scrollToShowSelected();
@@ -1645,6 +1731,54 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return handled;
 }
 
+BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
+{
+	S32 column_index = getColumnIndexFromOffset(x);
+	LLScrollListColumn* columnp = getColumn(column_index);
+
+	if (columnp == NULL) return FALSE;
+
+	BOOL handled = FALSE;
+	// show tooltip for full name of hovered item if it has been truncated
+	LLScrollListItem* hit_item = hitItem(x, y);
+	if (hit_item)
+	{
+		LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+		if (!hit_cell) return FALSE;
+		S32 cell_required_width = hit_cell->getContentWidth();
+		if (hit_cell 
+			&& hit_cell->isText() 
+			&& cell_required_width > columnp->mWidth)
+		{
+
+			S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
+			S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item));
+			LLRect cell_rect;
+			cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->mWidth, mLineHeight);
+			// Convert rect local to screen coordinates
+			localPointToScreen( 
+				cell_rect.mLeft, cell_rect.mBottom, 
+				&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+			localPointToScreen(
+				cell_rect.mRight, cell_rect.mTop, 
+				&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+
+			msg = hit_cell->getValue().asString();
+			handled = TRUE;
+		}
+	}
+
+	// otherwise, look for a tooltip associated with this column
+	LLColumnHeader* headerp = columnp->mHeader;
+	if (headerp && !handled)
+	{
+		headerp->handleToolTip(x, y, msg, sticky_rect_screen);
+		handled = !msg.empty();
+	}
+
+	return handled;
+}
+
 BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 {
 	if (!mCanSelect) return FALSE;
@@ -1652,6 +1786,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 	BOOL selection_changed = FALSE;
 
 	LLScrollListItem* hit_item = hitItem(x, y);
+
 	if( hit_item )
 	{
 		if( mAllowMultipleSelection )
@@ -1686,6 +1821,11 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						{
 							selectItem(item, FALSE);
 							selecting = !selecting;
+							if (hit_item == lastSelected)
+							{
+								// stop selecting now, since we just clicked on our last selected item
+								selecting = FALSE;
+							}
 						}
 						if (selecting)
 						{
@@ -1726,9 +1866,6 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 			selectItem(hit_item);
 		}
 
-		hit_item->handleClick(x - mBorderThickness - LIST_BORDER_PAD, 
-									1, mask);
-
 		selection_changed = mSelectionChanged;
 		if (mCommitOnSelectionChange)
 		{
@@ -1750,19 +1887,17 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 
 BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+	BOOL handled = childrenHandleMouseDown(x, y, mask) != NULL;
 
 	if( !handled )
 	{
 		// set keyboard focus first, in case click action wants to move focus elsewhere
 		setFocus(TRUE);
 
-		// clear selection changed flag so because user is starting a selection operation
+		// clear selection changed flag because user is starting a selection operation
 		mSelectionChanged = FALSE;
 
-		gFocusMgr.setMouseCapture(this);
-		selectItemAt(x, y, mask);
-		mNeedsScroll = TRUE;
+		handleClick(x, y, mask);
 	}
 
 	return TRUE;
@@ -1798,19 +1933,74 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
 	//BOOL handled = FALSE;
 	if(getVisible())
 	{
-		// Offer the click to the children, even if we aren't enabled
-		// so the scroll bars will work.
-		if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
+		BOOL handled = handleClick(x, y, mask);
+
+		if (!handled)
 		{
-			if( mCanSelect && mOnDoubleClickCallback )
+			// Offer the click to the children, even if we aren't enabled
+			// so the scroll bars will work.
+			if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
 			{
-				mOnDoubleClickCallback( mCallbackUserData );
+				if( mCanSelect && mOnDoubleClickCallback )
+				{
+					mOnDoubleClickCallback( mCallbackUserData );
+				}
 			}
 		}
 	}
 	return TRUE;
 }
 
+BOOL LLScrollListCtrl::handleClick(S32 x, S32 y, MASK mask)
+{
+	// which row was clicked on?
+	LLScrollListItem* hit_item = hitItem(x, y);
+	if (!hit_item) return FALSE;
+
+	// get appropriate cell from that row
+	S32 column_index = getColumnIndexFromOffset(x);
+	LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+	if (!hit_cell) return FALSE;
+
+	// select item (thus deselecting any currently selected item)
+	// only if item is not already selected
+	if (!hit_item->getSelected())
+	{
+		selectItemAt(x, y, mask);
+		gFocusMgr.setMouseCapture(this);
+		mNeedsScroll = TRUE;
+	}
+
+	if (hit_cell->handleClick())
+	{
+		// propagate value of this cell to other selected items
+		// and commit the respective widgets
+		LLSD item_value = hit_cell->getValue();
+		for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
+		{
+			LLScrollListItem* item = *iter;
+			if (item->getSelected())
+			{
+				LLScrollListCell* cellp = item->getColumn(column_index);
+				cellp->setValue(item_value);
+				cellp->onCommit();
+			}
+		}
+		//FIXME: find a better way to signal cell changes
+		onCommit();
+		return  TRUE;
+	}
+	else
+	{
+		// treat this as a normal single item selection
+		selectItemAt(x, y, mask);
+		gFocusMgr.setMouseCapture(this);
+		mNeedsScroll = TRUE;
+		// do not stop click processing (click callback, etc)
+		return FALSE;
+	}
+}
+
 LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
 {
 	// Excludes disabled items.
@@ -1847,6 +2037,59 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
 	return hit_item;
 }
 
+S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x)
+{
+	// which column did we hit?
+	S32 left = 0;
+	S32 right = 0;
+	S32 width = 0;
+	S32 column_index = 0;
+
+	ordered_columns_t::const_iterator iter = mColumnsIndexed.begin();
+	ordered_columns_t::const_iterator end = mColumnsIndexed.end();
+	for ( ; iter != end; ++iter)
+	{
+		width = (*iter)->mWidth + mColumnPadding;
+		right += width;
+		if (left <= x && x < right )
+		{
+			break;
+		}
+		
+		// set left for next column as right of current column
+		left = right;
+		column_index++;
+	}
+
+	return llclamp(column_index, 0, getNumColumns() - 1);
+}
+
+
+S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index)
+{
+	S32 column_offset = 0;
+	ordered_columns_t::const_iterator iter = mColumnsIndexed.begin();
+	ordered_columns_t::const_iterator end = mColumnsIndexed.end();
+	for ( ; iter != end; ++iter)
+	{
+		if (index-- <= 0)
+		{
+			return column_offset;
+		}
+		column_offset += (*iter)->mWidth + mColumnPadding;
+	}
+
+	// when running off the end, return the rightmost pixel
+	return mItemListRect.mRight;
+}
+
+S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index)
+{
+	S32 row_bottom = ((mItemListRect.mTop - (index - mScrollLines)) * mLineHeight) 
+						- mLineHeight;
+	return row_bottom;
+}
+
 
 BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 {
@@ -1860,7 +2103,8 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 			mNeedsScroll = TRUE;
 		}
 	}
-	else if (mCanSelect)
+	else 
+	if (mCanSelect)
 	{
 		LLScrollListItem* item = hitItem(x, y);
 		if (item)
@@ -1875,13 +2119,6 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 
 	handled = LLUICtrl::handleHover( x, y, mask );
 
-	//if( !handled )
-	//{
-	//	// Opaque
-	//	getWindow()->setCursor(UI_CURSOR_ARROW);
-	//	lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
-	//	handled = TRUE;
-	//}
 	return handled;
 }
 
@@ -2082,7 +2319,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_
 			if (cellp)
 			{
 				// Only select enabled items with matching first characters
-				LLWString item_label = utf8str_to_wstring(cellp->getText());
+				LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
 				if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
 				{
 					selectItem(item);
@@ -2176,7 +2413,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
 		LLScrollListCell* cellp = itemp->getColumn(mSearchColumn);
 		if (cellp)
 		{
-			cellp->highlightText(0, 0);
+			cellp->highlightText(0, 0);	
 		}
 		mSelectionChanged = TRUE;
 	}
@@ -2202,38 +2439,52 @@ BOOL LLScrollListCtrl::isSorted()
 	return mSorted;
 }
 
-// Called by scrollbar
-//static
-void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+struct SameSortColumn
 {
-	LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
-	self->mScrollLines = new_pos;
-}
+	SameSortColumn(S32 column) : mColumn(column) {}
+	S32 mColumn;
 
+	bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; }
+};
 
-// First column is column 0
-void  LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
+BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
 {
-	if (!mSorted || mSortColumn != column)
+	sort_column_t new_sort_column(column, ascending);
+
+	if (mSortColumns.empty())
 	{
-		mSortColumn = column;
-		std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
-		setSorted(TRUE);
+		mSortColumns.push_back(new_sort_column);
+		return TRUE;
 	}
+	else
+	{	
+		// grab current sort column
+		sort_column_t cur_sort_column = mSortColumns.back();
+		
+		// remove any existing sort criterion referencing this column
+		// and add the new one
+		remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column)); 
+		mSortColumns.push_back(new_sort_column);
 
-	// just reverse the list if changing sort order
-	if(mSortAscending != ascending)
-	{
-		std::reverse(mItemList.begin(), mItemList.end());
-		mSortAscending = ascending;
+		// did the sort criteria change?
+		return (cur_sort_column != new_sort_column);
 	}
 }
 
+// Called by scrollbar
+//static
+void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+{
+	LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
+	self->mScrollLines = new_pos;
+}
+
+
 void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
 {
 	if (name.empty())
 	{
-		sortByColumn(mSortColumn, mSortAscending);
+		sortItems();
 		return;
 	}
 
@@ -2244,6 +2495,26 @@ void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
 	}
 }
 
+// First column is column 0
+void  LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
+{
+	if (setSort(column, ascending))
+	{
+		sortItems();
+	}
+}
+
+void LLScrollListCtrl::sortItems()
+{
+	// do stable sort to preserve any previous sorts
+	std::stable_sort(
+		mItemList.begin(), 
+		mItemList.end(), 
+		SortScrollListItem(mSortColumns));
+
+	setSorted(TRUE);
+}
+
 S32 LLScrollListCtrl::getScrollPos()
 {
 	return mScrollbar->getDocPos();
@@ -2465,7 +2736,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
 	LLSD columns;
 	S32 index = 0;
 	LLXMLNodePtr child;
-	S32 total_static = 0, num_dynamic = 0;
+	S32 total_static = 0;
 	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
 	{
 		if (child->hasName("column"))
@@ -2491,8 +2762,10 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
 			S32 columnwidth = -1;
 			child->getAttributeS32("width", columnwidth);	
 
+			LLString tooltip;
+			child->getAttributeString("tool_tip", tooltip);
+
 			if(!columndynamicwidth) total_static += columnwidth;
-			else ++num_dynamic;
 
 			F32 columnrelwidth = 0.f;
 			child->getAttributeF32("relwidth", columnrelwidth);
@@ -2509,10 +2782,11 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
 			columns[index]["relwidth"] = columnrelwidth;
 			columns[index]["dynamicwidth"] = columndynamicwidth;
 			columns[index]["halign"] = (S32)h_align;
+			columns[index]["tool_tip"] = tooltip;
+			
 			index++;
 		}
 	}
-	scroll_list->setNumDynamicColumns(num_dynamic);
 	scroll_list->setTotalStaticColumnWidth(total_static);
 	scroll_list->setColumnHeadings(columns);
 
@@ -2665,7 +2939,7 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
 	LLString name = column["name"].asString();
 	if (mColumns.empty())
 	{
-		mDefaultColumn = 0;
+		mDefaultColumnName = name;
 	}
 	// if no column name provided, just use ordinal as name
 	if (name.empty())
@@ -2691,6 +2965,7 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
 			}
 			else if(new_column->mDynamicWidth)
 			{
+				mNumDynamicWidthColumns++;
 				new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
 			}
 			S32 top = mItemListRect.mTop;
@@ -2724,17 +2999,16 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
 				new_column->mHeader->setLabel(new_column->mLabel);
 				//new_column->mHeader->setLabel(new_column->mLabel);
 			}
+
+			new_column->mHeader->setToolTip(column["tool_tip"].asString());
+
 			//RN: although it might be useful to change sort order with the keyboard,
 			// mixing tab stops on child items along with the parent item is not supported yet
 			new_column->mHeader->setTabStop(FALSE);
 			addChild(new_column->mHeader);
 			new_column->mHeader->setVisible(mDisplayColumnHeaders);
 
-
-			// Move scroll to front
-			removeChild(mScrollbar);
-			addChild(mScrollbar);
-		
+			sendChildToFront(mScrollbar);
 		}
 	}
 	updateColumns();
@@ -2753,18 +3027,18 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 
 	LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
 	bool ascending = column->mSortAscending;
-	if (column->mSortingColumn != column->mName)
+	if (column->mSortingColumn != column->mName
+		&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
 	{
-		if (parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
-		{
-			LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
-			column_index = info_redir.mIndex;
-		}
+		LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
+		column_index = info_redir.mIndex;
 	}
 
-	if (column_index == parent->mSortColumn)
+	// if this column is the primary sort key, reverse the direction
+	sort_column_t cur_sort_column;
+	if (!parent->mSortColumns.empty() && parent->mSortColumns.back().first == column_index)
 	{
-		ascending = !parent->mSortAscending;
+		ascending = !parent->mSortColumns.back().second;
 	}
 
 	parent->sortByColumn(column_index, ascending);
@@ -2777,12 +3051,17 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 
 std::string LLScrollListCtrl::getSortColumnName()
 {
-	LLScrollListColumn* column = mSortColumn >= 0 ? mColumnsIndexed[mSortColumn] : NULL;
+	LLScrollListColumn* column = mSortColumns.empty() ? NULL : mColumnsIndexed[mSortColumns.back().first];
 
 	if (column) return column->mName;
 	else return "";
 }
 
+BOOL LLScrollListCtrl::needsSorting()
+{
+	return !mSortColumns.empty();
+}
+
 void LLScrollListCtrl::clearColumns()
 {
 	std::map<LLString, LLScrollListColumn>::iterator itor;
@@ -2796,6 +3075,7 @@ void LLScrollListCtrl::clearColumns()
 		}
 	}
 	mColumns.clear();
+	mSortColumns.clear();
 }
 
 void LLScrollListCtrl::setColumnLabel(const LLString& column, const LLString& label)
@@ -2851,11 +3131,6 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 	{
 		LLString column = (*itor)["column"].asString();
 
-		if (mColumns.size() == 0)
-		{
-			mDefaultColumn = 0;
-		}
-
 		LLScrollListColumn* columnp = NULL;
 
 		// empty columns strings index by ordinal
@@ -2895,6 +3170,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 		LLString type = (*itor)["type"].asString();
 		BOOL has_color = (*itor).has("color");
 		LLColor4 color = ((*itor)["color"]);
+		BOOL enabled = !(*itor).has("enabled") || (*itor)["enabled"].asBoolean() == true;
 
 		const LLFontGL *font = gResMgr->getRes(fontname);
 		if (!font)
@@ -2906,7 +3182,8 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 		if (type == "icon")
 		{
 			LLUUID image_id = value.asUUID();
-			LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id);
+			// don't use special image with UUID::null, just don't draw an image
+			LLImageGL* icon = image_id.isNull() ? NULL : LLUI::sImageProvider->getImageByID(image_id);
 			LLScrollListIcon* cell = new LLScrollListIcon(icon, width, image_id);
 			if (has_color)
 			{
@@ -2916,8 +3193,10 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 		}
 		else if (type == "checkbox")
 		{
-			LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(),
-														LLRect(0, 0, width, width), "label");
+			LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl("check",
+														LLRect(0, width, width, 0), " ");
+			ctrl->setEnabled(enabled);
+			ctrl->setValue(value);
 			LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
 			if (has_color)
 			{
@@ -3070,18 +3349,12 @@ void LLScrollListCtrl::onFocusReceived()
 {
 	// forget latent selection changes when getting focus
 	mSelectionChanged = FALSE;
+	LLUICtrl::onFocusReceived();
 }
 
 //virtual 
 void LLScrollListCtrl::onFocusLost()
 {
-	if (mIsPopup)
-	{
-		if (getParent())
-		{
-			getParent()->onFocusLost();
-		}
-	}
 	if (hasMouseCapture())
 	{
 		gFocusMgr.setMouseCapture(NULL);
@@ -3133,11 +3406,11 @@ void LLColumnHeader::draw()
 {
 	if( getVisible() )
 	{
-		mDrawArrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
+		BOOL draw_arrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
 
 		BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
-		mArrowImage = is_ascending ? LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("up_arrow.tga")))
-			: LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("down_arrow.tga")));
+		mButton->setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+		mArrowImage = mButton->getImageOverlay()->getImage();
 
 		//BOOL clip = mRect.mRight > mColumn->mParentCtrl->getItemListRect().getWidth();
 		//LLGLEnable scissor_test(clip ? GL_SCISSOR_TEST : GL_FALSE);
@@ -3237,11 +3510,11 @@ void LLColumnHeader::showList()
 			{
 				if (mColumn->mParentCtrl->getSortAscending())
 				{
-					low_item_text = cell->getText();
+					low_item_text = cell->getValue().asString();
 				}
 				else
 				{
-					high_item_text = cell->getText();
+					high_item_text = cell->getValue().asString();
 				}
 			}
 		}
@@ -3254,11 +3527,11 @@ void LLColumnHeader::showList()
 			{
 				if (mColumn->mParentCtrl->getSortAscending())
 				{
-					high_item_text = cell->getText();
+					high_item_text = cell->getValue().asString();
 				}
 				else
 				{
-					low_item_text = cell->getText();
+					low_item_text = cell->getValue().asString();
 				}
 			}
 		}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index a98a411efa8c1a52d12143f57db215d54e7a47b1..001e10184b65d46c0ea8d7865fbb7a3c46c612df 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -59,14 +59,16 @@ class LLScrollListCell
 	virtual ~LLScrollListCell() {};
 	virtual void			drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const = 0;		// truncate to given width, if possible
 	virtual S32				getWidth() const = 0;
+	virtual S32				getContentWidth() const { return 0; }
 	virtual S32				getHeight() const = 0;
-	virtual const LLString&	getText() const { return LLString::null; }
-	virtual const LLString&	getTextLower() const { return LLString::null; }
+	virtual const LLSD		getValue() const { return LLString::null; }
+	virtual void			setValue(LLSD value) { }
 	virtual BOOL			getVisible() const { return TRUE; }
 	virtual void			setWidth(S32 width) = 0;
 	virtual void			highlightText(S32 offset, S32 num_chars) {}
 	virtual BOOL			isText() = 0;
 	virtual void			setColor(const LLColor4&) = 0;
+	virtual void			onCommit() {};
 
 	virtual BOOL	handleClick() { return FALSE; }
 	virtual	void	setEnabled(BOOL enable) { }
@@ -96,20 +98,24 @@ class LLScrollListText : public LLScrollListCell
 
 	virtual void    drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;
 	virtual S32		getWidth() const			{ return mWidth; }
+	virtual S32		getContentWidth() const;
 	virtual void	setWidth(S32 width)			{ mWidth = width; }
 	virtual S32		getHeight() const			{ return llround(mFont->getLineHeight()); }
-	virtual const LLString&		getText() const		{ return mText.getString(); }
+	virtual const LLSD		getValue() const		{ return LLSD(mText.getString()); }
 	virtual BOOL	getVisible() const  { return mVisible; }
 	virtual void	highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;}
-	void			setText(const LLStringExplicit& text);
+
 	virtual void	setColor(const LLColor4&);
 	virtual BOOL	isText() { return TRUE; }
 
+	void			setText(const LLStringExplicit& text);
+	void			setFontStyle(const U8 font_style) { mFontStyle = font_style; }
+
 private:
 	LLUIString		mText;
 	const LLFontGL*	mFont;
 	LLColor4*		mColor;
-	const U8		mFontStyle;
+	U8				mFontStyle;
 	LLFontGL::HAlign mFontAlignment;
 	S32				mWidth;
 	BOOL			mVisible;
@@ -128,16 +134,16 @@ class LLScrollListIcon : public LLScrollListCell
 	/*virtual*/ ~LLScrollListIcon();
 	virtual void	drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;
 	virtual S32		getWidth() const			{ return mWidth; }
-	virtual S32		getHeight() const			{ return mIcon->getHeight(); }
-	virtual const LLString& getText() const { return mImageUUID; }
-	virtual const LLString& getTextLower() const { return mImageUUID; }
+	virtual S32		getHeight() const			{ return mIcon ? mIcon->getHeight() : 0; }
+	virtual const LLSD		getValue() const { return LLSD(mImageUUID); }
 	virtual void	setWidth(S32 width)			{ mWidth = width; }
 	virtual void	setColor(const LLColor4&);
 	virtual BOOL	isText() { return FALSE; }
+	virtual void	setValue(LLSD value);
 
 private:
 	LLPointer<LLImageGL> mIcon;
-	LLString mImageUUID;
+	LLUUID mImageUUID;
 	S32 mWidth;
 	LLColor4 mColor;
 };
@@ -151,9 +157,12 @@ class LLScrollListCheck : public LLScrollListCell
 	virtual S32		getWidth() const			{ return mWidth; }
 	virtual S32		getHeight() const			{ return 0; } 
 	virtual void	setWidth(S32 width)			{ mWidth = width; }
+	virtual const LLSD	getValue() const { return mCheckBox->getValue(); }
+	virtual void	setValue(LLSD value) { mCheckBox->setValue(value); }
+	virtual void	onCommit() { mCheckBox->onCommit(); }
 
 	virtual BOOL	handleClick();
-	virtual void	setEnabled(BOOL enable)		{ if (mCheckBox) mCheckBox->setEnabled(enable); }
+	virtual void	setEnabled(BOOL enable)		{ mCheckBox->setEnabled(enable); }
 	virtual void	setColor(const LLColor4& color) {};
 
 	LLCheckBoxCtrl*	getCheckBox()				{ return mCheckBox; }
@@ -266,6 +275,7 @@ class LLColumnHeader : public LLComboBox
 
 	/*virtual*/ void draw();
 	/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+
 	/*virtual*/ void showList();
 	/*virtual*/ LLView*	findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding);
 	/*virtual*/ void userSetShape(const LLRect& new_rect);
@@ -333,8 +343,6 @@ class LLScrollListItem
 
 	LLScrollListCell *getColumn(const S32 i) const	{ if (0 <= i && i < (S32)mColumns.size()) { return mColumns[i]; } return NULL; }
 
-	virtual BOOL handleClick(S32 x, S32 y, MASK mask);
-
 	LLString getContentsCSV();
 
 private:
@@ -370,9 +378,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	void			deleteAllItems() { clearRows(); }
 	
 	// Sets an array of column descriptors
-	void 	   		 setColumnHeadings(LLSD headings);
-	// Numerical based sort by column function (used by LLComboBox)
-	void   			 sortByColumn(U32 column, BOOL ascending);
+	void 	   		setColumnHeadings(LLSD headings);
+	void   			sortByColumn(U32 column, BOOL ascending);
 	
 	// LLCtrlListInterface functions
 	virtual S32  getItemCount() const;
@@ -421,18 +428,20 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	BOOL			isSorted();
 
 	virtual BOOL	isSelected(LLSD value);
-	
+
+	BOOL			handleClick(S32 x, S32 y, MASK mask);
 	BOOL			selectFirstItem();
 	BOOL			selectNthItem( S32 index );
 	BOOL			selectItemAt(S32 x, S32 y, MASK mask);
 	
-	void			deleteSingleItem( S32 index ) ;
+	void			deleteSingleItem( S32 index );
+	void			deleteItems(const LLSD& sd);
 	void 			deleteSelectedItems();
 	void			deselectAllItems(BOOL no_commit_on_change = FALSE);	// by default, go ahead and commit on selection change
 
 	void			highlightNthItem( S32 index );
 	void			setDoubleClickCallback( void (*cb)(void*) ) { mOnDoubleClickCallback = cb; }
-	void			setMaxiumumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; }
+	void			setMaximumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; }
 	void			setSortChangedCallback( void (*cb)(void*) ) { mOnSortChangedCallback = cb; }
 
 	void			swapWithNext(S32 index);
@@ -449,11 +458,12 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	LLScrollListItem* addSimpleItem( const LLString& item_text, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE );
 	// Add an item with an associated LLSD
 	LLScrollListItem* addSimpleItem(const LLString& item_text, LLSD sd, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, S32 column_width = 0 );
+	LLScrollListItem* addSeparator(EAddPosition pos);
 
 	BOOL			selectSimpleItem( const LLString& item, BOOL case_sensitive = TRUE );		// FALSE if item not found
 	BOOL			selectSimpleItemByPrefix(const LLString& target, BOOL case_sensitive);
 	BOOL			selectSimpleItemByPrefix(const LLWString& target, BOOL case_sensitive);
-	const LLString&	getSimpleSelectedItem(S32 column = 0) const;
+	const LLString	getSimpleSelectedItem(S32 column = 0) const;
 	LLSD			getSimpleSelectedValue();
 
 	// DEPRECATED: Use LLSD versions of addSimpleItem() and getSimpleSelectedValue().
@@ -472,6 +482,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	LLScrollListItem*	getFirstData() const;
 	LLScrollListItem*	getLastData() const;
 	std::vector<LLScrollListItem*>	getAllData() const;
+
+	LLScrollListItem*	getItem(const LLSD& sd) const;
 	
 	void setAllowMultipleSelection(BOOL mult )	{ mAllowMultipleSelection = mult; }
 
@@ -501,28 +513,34 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 
 	S32				getSearchColumn() { return mSearchColumn; }
 	void			setSearchColumn(S32 column) { mSearchColumn = column; }
+	S32				getColumnIndexFromOffset(S32 x);
+	S32				getColumnOffsetFromIndex(S32 index);
+	S32				getRowOffsetFromIndex(S32 index);
 
 	void			clearSearchString() { mSearchString.clear(); }
 
 	// Overridden from LLView
-	virtual void    draw();
-	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleDoubleClick(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
-	virtual BOOL	handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
-	virtual BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
-	virtual void	setEnabled(BOOL enabled);
-	virtual void	setFocus( BOOL b );
-	virtual void	onFocusReceived();
-	virtual void	onFocusLost();
+	/*virtual*/ void    draw();
+	/*virtual*/ BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleDoubleClick(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
+	/*virtual*/ BOOL	handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
+	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
+	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect);
+	/*virtual*/ void	setEnabled(BOOL enabled);
+	/*virtual*/ void	setFocus( BOOL b );
+	/*virtual*/ void	onFocusReceived();
+	/*virtual*/ void	onFocusLost();
+	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
 	virtual BOOL	isDirty() const;
 	virtual void	resetDirty();		// Clear dirty state
 
-	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	virtual void	arrange(S32 max_width, S32 max_height);
+	virtual void	updateLayout();
+	virtual void	fitContents(S32 max_width, S32 max_height);
+
 	virtual LLRect	getRequiredRect();
 	static  BOOL    rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row);
 
@@ -534,12 +552,12 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	static void onClickColumn(void *userdata);
 
 	void updateColumns();
-	void updateMaxContentWidth(LLScrollListItem* changed_item);
+	void calcMaxContentWidth(LLScrollListItem* changed_item);
+	S32 getMaxContentWidth() { return mMaxContentWidth; }
 
 	void setDisplayHeading(BOOL display);
 	void setHeadingHeight(S32 heading_height);
 	void setCollapseEmptyColumns(BOOL collapse);
-	void setIsPopup(BOOL is_popup) { mIsPopup = is_popup; }
 
 	LLScrollListItem*	hitItem(S32 x,S32 y);
 	virtual void		scrollToShowSelected();
@@ -564,9 +582,11 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	void setTotalStaticColumnWidth(int width) { mTotalStaticColumnWidth = width; }
 
 	std::string     getSortColumnName();
-	BOOL			getSortAscending() { return mSortAscending; }
+	BOOL			getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
+	BOOL			needsSorting();
 
 	S32		selectMultiple( LLDynamicArray<LLUUID> ids );
+	void			sortItems();
 
 protected:
 	// "Full" interface: use this when you're creating a list that has one or more of the following:
@@ -596,6 +616,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	void			deselectItem(LLScrollListItem* itemp);
 	void			commitIfChanged();
 	void			setSorted(BOOL sorted);
+	BOOL			setSort(S32 column, BOOL ascending);
 
 protected:
 	S32				mCurIndex;			// For get[First/Next]Data
@@ -616,7 +637,6 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	BOOL			mCanSelect;
 	BOOL			mDisplayColumnHeaders;
 	BOOL			mCollapseEmptyColumns;
-	BOOL			mIsPopup;
 
 	typedef std::deque<LLScrollListItem *> item_list;
 	item_list		mItemList;
@@ -626,7 +646,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	S32				mMaxItemCount; 
 
 	LLRect			mItemListRect;
-
+	S32				mMaxContentWidth;
 	S32             mColumnPadding;
 
 	BOOL			mBackgroundVisible;
@@ -652,22 +672,29 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	LLWString		mSearchString;
 	LLFrameTimer	mSearchTimer;
 	
-	LLString		mDefaultColumn;
+	LLString		mDefaultColumnName;
 
 	S32				mSearchColumn;
 	S32				mNumDynamicWidthColumns;
 	S32				mTotalStaticColumnWidth;
 
 	S32				mSortColumn;
+	S32				mSecondarySortColumn;
+	BOOL			mSecondarySortAscending;
 	BOOL			mSortAscending;
 	BOOL			mSorted;
-
+	
 	std::map<LLString, LLScrollListColumn> mColumns;
-	std::vector<LLScrollListColumn*> mColumnsIndexed;
 
 	BOOL			mDirty;
 	S32				mOriginalSelection;
 
+	typedef std::vector<LLScrollListColumn*> ordered_columns_t;
+	ordered_columns_t	mColumnsIndexed;
+
+	typedef std::pair<S32, BOOL> sort_column_t;
+	std::vector<sort_column_t>	mSortColumns;
+
 public:
 	// HACK:  Did we draw one selected item this frame?
 	BOOL mDrewSelected;
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 29626c25d628497fdd58adf25664d2aed66369bf..bd91d562aa05ecd969344fc2091714680a0f88ae 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -41,9 +41,6 @@
 #include "llcontrol.h"
 #include "llimagegl.h"
 
-const S32 THUMB_WIDTH = 8;
-const S32 TRACK_HEIGHT = 6;
-
 LLSlider::LLSlider( 
 	const LLString& name,
 	const LLRect& rect,
@@ -65,20 +62,24 @@ LLSlider::LLSlider(
 	mIncrement( increment ),
 	mVolumeSlider( volume ),
 	mMouseOffset( 0 ),
-	mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
-	mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
 	mTrackColor(		LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
 	mThumbOutlineColor(	LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
 	mThumbCenterColor(	LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
-	mDisabledThumbColor(LLUI::sColorsGroup->getColor( "SliderDisabledThumbColor" ) ),
 	mMouseDownCallback( NULL ),
 	mMouseUpCallback( NULL )
 {
+	mThumbImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-thumb_dark.tga")));
+	mTrackImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-groove_dark.tga")));
+	mTrackHighlightImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-highlight.tga")));
+
 	// properly handle setting the starting thumb rect
 	// do it this way to handle both the operating-on-settings
 	// and standalone ways of using this
 	setControlName(control_name, NULL);
 	setValue(getValueF32());
+
+	updateThumbRect();
+	mDragStartThumbRect = mThumbRect;
 }
 
 EWidgetType LLSlider::getWidgetType() const
@@ -107,17 +108,26 @@ void LLSlider::setValue(F32 value, BOOL from_event)
 	}
 
 	mValue = value;
+	updateThumbRect();
+}
 
+void LLSlider::updateThumbRect()
+{
 	F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
 
-	S32 left_edge = THUMB_WIDTH/2;
-	S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
+	S32 thumb_width = mThumbImage->getWidth();
+	S32 thumb_height = mThumbImage->getHeight();
+	S32 left_edge = (thumb_width / 2);
+	S32 right_edge = mRect.getWidth() - (thumb_width / 2);
 
 	S32 x = left_edge + S32( t * (right_edge - left_edge) );
-	mThumbRect.mLeft = x - (THUMB_WIDTH/2);
-	mThumbRect.mRight = x + (THUMB_WIDTH/2);
+	mThumbRect.mLeft = x - (thumb_width / 2);
+	mThumbRect.mRight = mThumbRect.mLeft + thumb_width;
+	mThumbRect.mBottom = getLocalRect().getCenterY() - (thumb_height / 2);
+	mThumbRect.mTop = mThumbRect.mBottom + thumb_height;
 }
 
+
 void LLSlider::setValueAndCommit(F32 value)
 {
 	F32 old_value = mValue;
@@ -139,8 +149,9 @@ BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
 {
 	if( hasMouseCapture() )
 	{
-		S32 left_edge = THUMB_WIDTH/2;
-		S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
+		S32 thumb_half_width = mThumbImage->getWidth()/2;
+		S32 left_edge = thumb_half_width;
+		S32 right_edge = mRect.getWidth() - (thumb_half_width);
 
 		x += mMouseOffset;
 		x = llclamp( x, left_edge, right_edge );
@@ -203,7 +214,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
 		// Find the offset of the actual mouse location from the center of the thumb.
 		if (mThumbRect.pointInRect(x,y))
 		{
-			mMouseOffset = (mThumbRect.mLeft + THUMB_WIDTH/2) - x;
+			mMouseOffset = (mThumbRect.mLeft + mThumbImage->getWidth()/2) - x;
 		}
 		else
 		{
@@ -251,6 +262,9 @@ void LLSlider::draw()
 {
 	if( getVisible() )
 	{
+		// since thumb image might still be decoding, need thumb to accomodate image size
+		updateThumbRect();
+
 		// Draw background and thumb.
 
 		// drawing solids requires texturing be disabled
@@ -260,104 +274,37 @@ void LLSlider::draw()
 
 		F32 opacity = mEnabled ? 1.f : 0.3f;
 		LLColor4 center_color = (mThumbCenterColor % opacity);
-		LLColor4 outline_color = (mThumbOutlineColor % opacity);
 		LLColor4 track_color = (mTrackColor % opacity);
 
-		LLImageGL* thumb_imagep = NULL;
-		
 		// Track
-		if (mVolumeSlider)
-		{
-			LLRect track(0, mRect.getHeight(), mRect.getWidth(), 0);
-
-			track.mBottom += 3;
-			track.mTop -= 1;
-			track.mRight -= 1;
-
-			gl_triangle_2d(track.mLeft, track.mBottom,
-						   track.mRight, track.mBottom,
-						   track.mRight, track.mTop,
-						   center_color,
-						   TRUE);
-			gl_triangle_2d(track.mLeft, track.mBottom,
-						   track.mRight, track.mBottom,
-						   track.mRight, track.mTop,
-						   outline_color,
-						   FALSE);
-		}
-		else
-		{
-			LLUUID thumb_image_id;
-			thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
-			thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
+		LLRect track_rect(mThumbImage->getWidth() / 2, 
+							getLocalRect().getCenterY() + (mTrackImage->getHeight() / 2), 
+							mRect.getWidth() - mThumbImage->getWidth() / 2, 
+							getLocalRect().getCenterY() - (mTrackImage->getHeight() / 2) );
 
-			S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
-			LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
+		gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 3, 3, track_rect.getWidth(), track_rect.getHeight(),
+											mTrackImage, track_color);
+		gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 3, 3, mThumbRect.mLeft, track_rect.getHeight(),
+											mTrackHighlightImage, track_color);
 
-			track_rect.stretch(-1);
-			gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
-											 thumb_imagep, track_color);
-		}
 
 		// Thumb
-		if (!thumb_imagep)
-		{
-			if (mVolumeSlider)
-			{
-				if (hasMouseCapture())
-				{
-					LLRect rect(mDragStartThumbRect);
-					gl_rect_2d( rect, outline_color );
-					rect.stretch(-1);
-					gl_rect_2d( rect, mThumbCenterColor % 0.3f );
-
-					if (hasFocus())
-					{
-						LLRect thumb_rect = mThumbRect;
-						thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
-						gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
-					}
-					gl_rect_2d( mThumbRect, mThumbOutlineColor );
-				}
-				else
-				{ 
-					if (hasFocus())
-					{
-						LLRect thumb_rect = mThumbRect;
-						thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
-						gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
-					}
-					LLRect rect(mThumbRect);
-					gl_rect_2d(rect, outline_color);
-					rect.stretch(-1);
-					gl_rect_2d( rect, center_color);
-				}
-			}
-			else
-			{
-				gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
-				if (hasMouseCapture())
-				{
-					gl_rect_2d(mDragStartThumbRect, center_color, FALSE);
-				}
-			}
-		}
-		else if( hasMouseCapture() )
+		if( hasMouseCapture() )
 		{
-			gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(), 
-											 thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
+			gl_draw_scaled_image(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(), 
+											 mThumbImage, mThumbCenterColor % 0.3f);
 
 			if (hasFocus())
 			{
 				F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
 				LLRect highlight_rect = mThumbRect;
 				highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
-				gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
-												 thumb_imagep, gFocusMgr.getFocusColor());
+				gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 0, 0, highlight_rect.getWidth(), highlight_rect.getHeight(),
+												 mThumbImage, gFocusMgr.getFocusColor(), TRUE);
 			}
 
-			gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), 
-											 thumb_imagep, mThumbOutlineColor, TRUE);
+			gl_draw_scaled_image(mThumbRect.mLeft, mThumbRect.mBottom, mThumbRect.getWidth(), mThumbRect.getHeight(), 
+											 mThumbImage, mThumbOutlineColor);
 
 		}
 		else
@@ -367,12 +314,12 @@ void LLSlider::draw()
 				F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
 				LLRect highlight_rect = mThumbRect;
 				highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
-				gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
-												 thumb_imagep, gFocusMgr.getFocusColor());
+				gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 0, 0, highlight_rect.getWidth(), highlight_rect.getHeight(),
+												 mThumbImage, gFocusMgr.getFocusColor(), TRUE);
 			}
 
-			gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), 
-											 thumb_imagep, center_color, TRUE);
+			gl_draw_scaled_image(mThumbRect.mLeft, mThumbRect.mBottom, mThumbRect.getWidth(), mThumbRect.getHeight(), 
+											 mThumbImage, center_color);
 		}
 		LLUICtrl::draw();
 	}
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 2641eaac74237fa6fbcd777e15cc842134dd062a..55be2afbcca6b3db8068e3c22e447062278fe400 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -36,6 +36,7 @@
 #include "v4color.h"
 
 class LLUICtrlFactory;
+class LLImageGL;
 
 class LLSlider : public LLUICtrl
 {
@@ -85,6 +86,7 @@ class LLSlider : public LLUICtrl
 
 protected:
 	void			setValueAndCommit(F32 value);
+	void			updateThumbRect();
 
 protected:
 	F32				mValue;
@@ -97,11 +99,14 @@ class LLSlider : public LLUICtrl
 	S32				mMouseOffset;
 	LLRect			mDragStartThumbRect;
 
+	LLImageGL*		mThumbImage;
+	LLImageGL*		mTrackImage;
+	LLImageGL*		mTrackHighlightImage;
+
 	LLRect			mThumbRect;
 	LLColor4		mTrackColor;
 	LLColor4		mThumbOutlineColor;
 	LLColor4		mThumbCenterColor;
-	LLColor4		mDisabledThumbColor;
 	
 	void			(*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
 	void			(*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index dd4a9941c59133c395130539baa372c7198f9047..3ff3a4f884cbb39073b96edd1e955f06191765ff 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -125,7 +125,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
 				&LLLineEditor::prevalidateFloat );
 			mEditor->setFollowsLeft();
 			mEditor->setFollowsBottom();
-			mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus );
+			mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this );
 			mEditor->setIgnoreTab(TRUE);
 			// don't do this, as selecting the entire text is single clicking in some cases
 			// and double clicking in others
@@ -150,7 +150,7 @@ LLSliderCtrl::~LLSliderCtrl()
 }
 
 // static
-void LLSliderCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata )
+void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
 {
 	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
 	llassert( caller == self->mEditor );
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index fa6c0bccaefb83adf9ba9ef74558f728cf8fbb19..de1c09639c3e628dab8ce9f27374d71bda87e28f 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -117,7 +117,7 @@ class LLSliderCtrl : public LLUICtrl
 	static void		onSliderMouseUp(LLUICtrl* caller,void* userdata);
 
 	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
-	static void		onEditorGainFocus(LLUICtrl* caller, void *userdata);
+	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
 	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
 
 private:
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 2be28140809a1032f375f322cf8c839bd9dd4dc1..c4b7de768ab1306d86fc709a4d44f0105631b974 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -128,7 +128,7 @@ LLSpinCtrl::LLSpinCtrl(	const LLString& name, const LLRect& rect, const LLString
 		&LLLineEditor::prevalidateFloat );
 	mEditor->setFollowsLeft();
 	mEditor->setFollowsBottom();
-	mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus );
+	mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this );
 	//RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
 	// than when it doesn't.  Instead, if you always have to double click to select all the text, 
 	// it's easier to understand
@@ -137,7 +137,7 @@ LLSpinCtrl::LLSpinCtrl(	const LLString& name, const LLRect& rect, const LLString
 	addChild(mEditor);
 
 	updateEditor();
-	setSpanChildren( TRUE );
+	setUseBoundingRect( TRUE );
 }
 
 LLSpinCtrl::~LLSpinCtrl()
@@ -230,7 +230,7 @@ void LLSpinCtrl::onDownBtn( void *userdata )
 }
 
 // static
-void LLSpinCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata )
+void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
 {
 	LLSpinCtrl* self = (LLSpinCtrl*) userdata;
 	llassert( caller == self->mEditor );
diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h
index f2c7b40cfe5a25e59b18afc082802b75ebf44583..5fc3ccdcc1e5619691a1cb3700375114db220129 100644
--- a/indra/llui/llspinctrl.h
+++ b/indra/llui/llspinctrl.h
@@ -113,7 +113,7 @@ class LLSpinCtrl
 	virtual void	draw();
 
 	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
-	static void		onEditorGainFocus(LLUICtrl* caller, void *userdata);
+	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
 	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
 
 	static void		onUpBtn(void *userdata);
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 1f932f758c9bfd6410fb129f6ec5c4c3a8dc0deb..2d3534e7bed115e5e8b31a7bcb99dacdc5a910bb 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -230,7 +230,7 @@ void LLStyle::setImage(const LLString& src)
 	}
 	else
 	{
-		mImagep = LLUI::sImageProvider->getUIImageByID(LLUUID(src));
+		mImagep = LLUI::sImageProvider->getImageByID(LLUUID(src));
 	}
 }
 
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 1ab11f3644db387f7a29638af9303256e2215bab..148060359fdd7e34cf07dbe06af6a645a46fcd73 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -156,7 +156,12 @@ void LLTabContainerCommon::lockTabs(S32 num_tabs)
 {
 	// count current tabs or use supplied value and ensure no new tabs get
 	// inserted between them
-	mLockedTabCount = num_tabs > 0 ? num_tabs : getTabCount();
+	mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
+}
+
+void LLTabContainerCommon::unlockTabs()
+{
+	mLockedTabCount = 0;
 }
 
 void LLTabContainerCommon::removeTabPanel(LLPanel* child)
@@ -557,7 +562,7 @@ void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name, con
 }
 
 void LLTabContainerCommon::setTitle(const LLString& title)
-{
+{	
 	if (mTitleBox)
 	{
 		mTitleBox->setText( title );
@@ -721,6 +726,14 @@ void LLTabContainerCommon::insertTuple(LLTabTuple * tuple, eInsertionPoint inser
 		// insert the new tab in the front of the list
 		mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
 		break;
+	case LEFT_OF_CURRENT:
+		// insert the new tab before the current tab (but not before mLockedTabCount)
+		{
+		tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
+		mTabList.insert(current_iter, tuple);
+		}
+		break;
+
 	case RIGHT_OF_CURRENT:
 		// insert the new tab after the current tab (but not before mLockedTabCount)
 		{
@@ -946,14 +959,14 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 	if( LLTabContainer::TOP == mTabPosition )
 	{
 		btn_rect.setLeftTopAndSize( 0, mRect.getHeight() - mTopBorderHeight + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
-		tab_img = "UIImgBtnTabTopOutUUID";
-		tab_selected_img = "UIImgBtnTabTopInUUID";
+		tab_img = "tab_top_blue.tga";
+		tab_selected_img = "tab_top_selected_blue.tga";
 	}
 	else
 	{
 		btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
-		tab_img = "UIImgBtnTabBottomOutUUID";
-		tab_selected_img = "UIImgBtnTabBottomInUUID";
+		tab_img = "tab_bottom_blue.tga";
+		tab_selected_img = "tab_bottom_selected_blue.tga";
 	}
 
 	if (placeholder)
@@ -979,7 +992,7 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 		LLButton* btn = new LLButton(
 			LLString(child->getName()) + " tab",
 			btn_rect, 
-			tab_img, tab_selected_img, "",
+			"", "", "",
 			&LLTabContainer::onTabBtn, NULL, // set userdata below
 			font,
 			trimmed_label, trimmed_label );
@@ -987,7 +1000,7 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 		btn->setVisible( FALSE );
 		btn->setToolTip( tooltip );
 		btn->setScaleImage(TRUE);
-		btn->setFixedBorder(14, 14);
+		btn->setImages(tab_img, tab_selected_img);
 
 		// Try to squeeze in a bit more text
 		btn->setLeftHPad( 4 );
@@ -1139,7 +1152,7 @@ BOOL LLTabContainer::selectTab(S32 which)
 
 	//if( gFocusMgr.childHasKeyboardFocus( this ) )
 	//{
-	//	gFocusMgr.setKeyboardFocus( NULL, NULL );
+	//	gFocusMgr.setKeyboardFocus( NULL );
 	//}
 
 	LLTabTuple* selected_tuple = mTabList[which];
@@ -1370,7 +1383,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 		{
 			LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton;
 			gFocusMgr.setMouseCapture(this);
-			gFocusMgr.setKeyboardFocus(tab_button, NULL);
+			gFocusMgr.setKeyboardFocus(tab_button);
 		}
 	}
 	return handled;
@@ -1475,7 +1488,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect )
 {
 	BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
-	if (!handled && mTabList.size() > 0 && getVisible() && pointInView( x, y ) ) 
+	if (!handled && mTabList.size() > 0) 
 	{
 		LLTabTuple* firsttuple = mTabList[0];
 
@@ -1645,12 +1658,12 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
 		mTotalTabWidth -= tuple->mButton->getRect().getWidth();
 
 		S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? 
-			tuple->mButton->getImageOverlay()->getWidth(0) :
+			tuple->mButton->getImageOverlay()->getImage()->getWidth(0) :
 			0;
 
 		tuple->mPadding = image_overlay_width;
 
-		tuple->mButton->setRightHPad(tuple->mPadding + LLBUTTON_H_PAD);
+		tuple->mButton->setRightHPad(6);
 		tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), 
 								tuple->mButton->getRect().getHeight());
 		// add back in button width to total tab strip width
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index c77547a7714a8931db5a8a06ced29c0d61e4bfe4..b72ecb8126b3b81d7885195e8a0add0076e0bd4a 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -54,6 +54,7 @@ class LLTabContainerCommon : public LLPanel
 	{
 		START,
 		END,
+		LEFT_OF_CURRENT,
 		RIGHT_OF_CURRENT
 	} eInsertionPoint;
 
@@ -91,6 +92,8 @@ class LLTabContainerCommon : public LLPanel
 							 eInsertionPoint insertion_point = END) = 0;
 	virtual void		addPlaceholder(LLPanel* child, const LLString& label);
 	virtual void		lockTabs(S32 num_tabs = 0);
+	virtual void		unlockTabs();
+	S32					getNumLockedTabs() { return mLockedTabCount; }
 
 	virtual void		enableTabButton(S32 which, BOOL enable);
 
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 8bd7b1509fca2688a3084146d35d1412a75b42dd..3b15e3a25ff9d8050c17b98216ff8b919648a220 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -56,6 +56,7 @@ LLTextBox::LLTextBox(const LLString& name, const LLRect& rect, const LLString& t
 	mBorderVisible( FALSE ),
 	mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
 	mBorderDropShadowVisible( FALSE ),
+	mUseEllipses( FALSE ),
 	mHPad(0),
 	mVPad(0),
 	mHAlign( LLFontGL::LEFT ),
@@ -84,6 +85,7 @@ LLTextBox::LLTextBox(const LLString& name, const LLString& text, F32 max_width,
 	mBorderVisible(FALSE),
 	mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
 	mBorderDropShadowVisible(FALSE),
+	mUseEllipses( FALSE ),
 	mHPad(0),
 	mVPad(0),
 	mHAlign(LLFontGL::LEFT),
@@ -393,7 +395,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
 			mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color,
 							mHAlign, mVAlign,
 							mFontStyle,
-							line_length, mRect.getWidth(), NULL, TRUE );
+							line_length, mRect.getWidth(), NULL, TRUE, mUseEllipses );
 			cur_pos += line_length + 1;
 			y -= llfloor(mFontGL->getLineHeight());
 		}
@@ -403,7 +405,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
 		mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color,
 						mHAlign, mVAlign, 
 						mFontStyle,
-						S32_MAX, mRect.getWidth(), NULL, TRUE);
+						S32_MAX, mRect.getWidth(), NULL, TRUE, mUseEllipses);
 	}
 }
 
@@ -481,7 +483,7 @@ LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
 		text_box->mFontStyle = LLFontGL::getStyleFromString(font_style);
 	}
 	
-	BOOL mouse_opaque;
+	BOOL mouse_opaque = text_box->getMouseOpaque();
 	if (node->getAttributeBOOL("mouse_opaque", mouse_opaque))
 	{
 		text_box->setMouseOpaque(mouse_opaque);
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index c7c79464a051dd2748b835dbd0aab95d68762a2a..d25452b941b1ebd596a007ee71d25b3f195c071a 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -79,6 +79,7 @@ class LLTextBox
 	void			setText( const LLStringExplicit& text );
 	void			setWrappedText(const LLStringExplicit& text, F32 max_width = -1.0);
 						// default width means use existing control width
+	void			setUseEllipses( BOOL use_ellipses )		{ mUseEllipses = use_ellipses; }
 	
 	void			setBackgroundVisible(BOOL visible)		{ mBackgroundVisible = visible; }
 	void			setBorderVisible(BOOL visible)			{ mBorderVisible = visible; }
@@ -124,6 +125,7 @@ class LLTextBox
 	
 	U8				mFontStyle; // style bit flags for font
 	BOOL			mBorderDropShadowVisible;
+	BOOL			mUseEllipses;
 
 	S32				mHPad;
 	S32				mVPad;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 5c8b7c7281835c5592598b9f451b8a5f265f5b8e..8b9353eb8e10ab69608e13701df9795ce3a6c6a5 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -310,9 +310,9 @@ LLTextEditor::LLTextEditor(
 	mWordWrap( FALSE ),
 	mTabToNextField( TRUE ),
 	mCommitOnFocusLost( FALSE ),
-	mTakesFocus( TRUE ),
 	mHideScrollbarForShortDocs( FALSE ),
 	mTakesNonScrollClicks( TRUE ),
+	mTrackBottom( TRUE ),
 	mAllowEmbeddedItems( allow_embedded_items ),
 	mAcceptCallingCardNames(FALSE),
 	mHandleEditKeysDirectly( FALSE ),
@@ -1141,46 +1141,42 @@ void LLTextEditor::selectAll()
 
 BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
 {
-	if (pointInView(x, y) && getVisible())
+	for ( child_list_const_iter_t child_it = getChildList()->begin();
+			child_it != getChildList()->end(); ++child_it)
 	{
-		for ( child_list_const_iter_t child_it = getChildList()->begin();
-			  child_it != getChildList()->end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
-			{
-				return TRUE;
-			}
-		}
-
-		if( mSegments.empty() )
+		LLView* viewp = *child_it;
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
 		{
 			return TRUE;
 		}
+	}
 
-		LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
-		if( cur_segment )
-		{
-			BOOL has_tool_tip = FALSE;
-			has_tool_tip = cur_segment->getToolTip( msg );
+	if( mSegments.empty() )
+	{
+		return TRUE;
+	}
 
-			if( has_tool_tip )
-			{
-				// Just use a slop area around the cursor
-				// Convert rect local to screen coordinates
-				S32 SLOP = 8;
-				localPointToScreen( 
-					x - SLOP, y - SLOP, 
-					&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
-				sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
-				sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
-			}
+	LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
+	if( cur_segment )
+	{
+		BOOL has_tool_tip = FALSE;
+		has_tool_tip = cur_segment->getToolTip( msg );
+
+		if( has_tool_tip )
+		{
+			// Just use a slop area around the cursor
+			// Convert rect local to screen coordinates
+			S32 SLOP = 8;
+			localPointToScreen( 
+				x - SLOP, y - SLOP, 
+				&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+			sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
+			sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
 		}
-		return TRUE;
 	}
-	return FALSE;
+	return TRUE;
 }
 
 BOOL LLTextEditor::handleScrollWheel(S32 x, S32 y, S32 clicks)
@@ -1263,7 +1259,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 		handled = TRUE;
 	}
 
-	if (mTakesFocus)
+	if (hasTabStop())
 	{
 		setFocus( TRUE );
 		handled = TRUE;
@@ -1436,11 +1432,6 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 
 	if( !handled && mTakesNonScrollClicks)
 	{
-		if (mTakesFocus)
-		{
-			setFocus( TRUE );
-		}
-		
 		setCursorAtLocalPos( x, y, FALSE );
 		deselect();
 
@@ -3160,6 +3151,9 @@ void LLTextEditor::draw()
 		}
 		LLView::draw();  // Draw children (scrollbar and border)
 	}
+	
+	// remember if we are supposed to be at the bottom of the buffer
+	mScrolledToBottom = isScrolledToBottom();
 }
 
 void LLTextEditor::reportBadKeystroke()
@@ -3328,6 +3322,17 @@ void LLTextEditor::changeLine( S32 delta )
 	unbindEmbeddedChars( mGLFont );
 }
 
+BOOL LLTextEditor::isScrolledToTop() 
+{ 
+	return mScrollbar->isAtBeginning(); 
+}
+
+BOOL LLTextEditor::isScrolledToBottom() 
+{ 
+	return mScrollbar->isAtEnd(); 
+}
+
+
 void LLTextEditor::startOfLine()
 {
 	S32 line, offset;
@@ -3448,6 +3453,13 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
 	LLView::reshape( width, height, called_from_parent );
 
+	// if scrolled to bottom, stay at bottom
+	// unless user is editing text
+	if (mScrolledToBottom && mTrackBottom && !hasFocus())
+	{
+		endOfDoc();
+	}
+
 	updateTextRect();
 
 	S32 line_height = llround( mGLFont->getLineHeight() );
@@ -4234,6 +4246,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
 	node->getAttributeBOOL("word_wrap", word_wrap);
 	setWordWrap(word_wrap);
 
+	node->getAttributeBOOL("track_bottom", mTrackBottom);
+
 	LLColor4 color;
 	if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color)) 
 	{
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 7049de7b89692dcb09b44ae8340f513a5c4b76fe..a2ce0d2c471c0841832562573346da8c47ff9576 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -206,13 +206,13 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 	void			setTabToNextField(BOOL b)				{ mTabToNextField = b; }
 	void			setCommitOnFocusLost(BOOL b)			{ mCommitOnFocusLost = b; }
 
-	// If takes focus, will take keyboard focus on click.
-	void			setTakesFocus(BOOL b)					{ mTakesFocus = b; }
-
 	// Hack to handle Notecards
 	virtual BOOL	importBuffer(const LLString& buffer );
 	virtual BOOL	exportBuffer(LLString& buffer );
 
+	// If takes focus, will take keyboard focus on click.
+	void			setTakesFocus(BOOL b)					{ mTakesFocus = b; }
+
 	void			setSourceID(const LLUUID& id) 			{ mSourceID = id; }
 	void 			setAcceptCallingCardNames(BOOL enable)	{ mAcceptCallingCardNames = enable; }
 
@@ -244,7 +244,10 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 	void			startOfLine();
 	void			endOfLine();
 	void			endOfDoc();
-	
+
+	BOOL			isScrolledToTop();
+	BOOL			isScrolledToBottom();
+
 	// Getters
 	const LLWString& getWText() const;
 	llwchar			getWChar(S32 pos);
@@ -439,6 +442,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 	BOOL			mTakesFocus;
 	BOOL			mHideScrollbarForShortDocs;
 	BOOL			mTakesNonScrollClicks;
+	BOOL			mTrackBottom;			// if true, keeps scroll position at bottom during resize
+	BOOL			mScrolledToBottom;
 
 	BOOL			mAllowEmbeddedItems;
 
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 00a230dff3cd77b41b57eb8b874259fd3294fe54..7561fe8b483179cb1575a3a0700e66b231c502f3 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -79,7 +79,7 @@ LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
 LLWindow*		LLUI::sWindow = NULL;
 LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
 BOOL            LLUI::sShowXUINames = FALSE;
-std::stack<LLRect> LLUI::sClipRectStack;
+std::stack<LLRect> LLScreenClipRect::sClipRectStack;
 
 //
 // Functions
@@ -410,39 +410,76 @@ void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max
 }
 
 
-void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color )
+void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect )
 {
-	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color );
+	if (NULL == image)
+	{
+		llwarns << "image == NULL; aborting function" << llendl;
+		return;
+	}
+	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect );
 }
 
-void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
 {
-	gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color );
+	if (NULL == image)
+	{
+		llwarns << "image == NULL; aborting function" << llendl;
+		return;
+	}
+	gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect );
 }
 
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color)
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect)
 {
-	stop_glerror();
-	F32 border_scale = 1.f;
-
 	if (NULL == image)
 	{
 		llwarns << "image == NULL; aborting function" << llendl;
 		return;
 	}
 
-	if (border_height * 2 > height)
-	{
-		border_scale = (F32)height / ((F32)border_height * 2.f);
-	}
-	if (border_width * 2 > width)
+	// scale screen size of borders down
+	F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
+	F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
+
+	LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction);
+	gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
+}
+
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect, const LLRectf& scale_rect)
+{
+	stop_glerror();
+
+	if (NULL == image)
 	{
-		border_scale = llmin(border_scale, (F32)width / ((F32)border_width * 2.f));
+		llwarns << "image == NULL; aborting function" << llendl;
+		return;
 	}
 
 	// scale screen size of borders down
-	S32 scaled_border_width = llfloor(border_scale * (F32)border_width);
-	S32 scaled_border_height = llfloor(border_scale * (F32)border_height);
+	LLRectf clipped_scale_rect = uv_rect;
+	clipped_scale_rect.intersectWith(scale_rect);
+
+	LLRect draw_rect(0, height, width, 0);
+	LLRect draw_scale_rect(llround((F32)image->getWidth() * scale_rect.mLeft),
+						llround((F32)image->getHeight() * scale_rect.mTop),
+						llround((F32)image->getWidth() * scale_rect.mRight),
+						llround((F32)image->getHeight() * scale_rect.mBottom));
+	// scale fixed region of image up with drawn region
+	draw_scale_rect.mRight += width - image->getWidth();
+	draw_scale_rect.mTop += height - image->getHeight();
+
+	S32 border_shrink_width = llmax(0, draw_scale_rect.mLeft - draw_scale_rect.mRight);
+	S32 border_shrink_height = llmax(0, draw_scale_rect.mBottom - draw_scale_rect.mTop);
+
+	F32 shrink_width_ratio = scale_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image->getWidth() * (1.f - scale_rect.getWidth()));
+	F32 shrink_height_ratio = scale_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image->getHeight() * (1.f - scale_rect.getHeight()));
+
+	F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
+	draw_scale_rect.mLeft = llround((F32)draw_scale_rect.mLeft * shrink_scale);
+	draw_scale_rect.mTop = llround(lerp((F32)height, (F32)draw_scale_rect.mTop, shrink_scale));
+	draw_scale_rect.mRight = llround(lerp((F32)width, (F32)draw_scale_rect.mRight, shrink_scale));
+	draw_scale_rect.mBottom = llround((F32)draw_scale_rect.mBottom * shrink_scale);
 
 	LLGLSUIDefault gls_ui;
 	
@@ -470,127 +507,124 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
 
 		glColor4fv(color.mV);
 		
-		F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
-		F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
-
 		glBegin(GL_QUADS);
 		{
 			// draw bottom left
-			glTexCoord2f(0.f, 0.f);
+			glTexCoord2d(uv_rect.mLeft, uv_rect.mBottom);
 			glVertex2i(0, 0);
 
-			glTexCoord2f(border_width_fraction, 0.f);
-			glVertex2i(scaled_border_width, 0);
+			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, 0);
 
-			glTexCoord2f(border_width_fraction, border_height_fraction);
-			glVertex2i(scaled_border_width, scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2f(0.f, border_height_fraction);
-			glVertex2i(0, scaled_border_height);
+			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(0, draw_scale_rect.mBottom);
 
 			// draw bottom middle
-			glTexCoord2f(border_width_fraction, 0.f);
-			glVertex2i(scaled_border_width, 0);
+			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, 0);
 
-			glTexCoord2f(1.f - border_width_fraction, 0.f);
-			glVertex2i(width - scaled_border_width, 0);
+			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, 0);
 
-			glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
-			glVertex2i(width - scaled_border_width, scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2f(border_width_fraction, border_height_fraction);
-			glVertex2i(scaled_border_width, scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
 			// draw bottom right
-			glTexCoord2f(1.f - border_width_fraction, 0.f);
-			glVertex2i(width - scaled_border_width, 0);
+			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, 0);
 
-			glTexCoord2f(1.f, 0.f);
+			glTexCoord2d(uv_rect.mRight, uv_rect.mBottom);
 			glVertex2i(width, 0);
 
-			glTexCoord2f(1.f, border_height_fraction);
-			glVertex2i(width, scaled_border_height);
+			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(width, draw_scale_rect.mBottom);
 
-			glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
-			glVertex2i(width - scaled_border_width, scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
 			// draw left 
-			glTexCoord2f(0.f, border_height_fraction);
-			glVertex2i(0, scaled_border_height);
+			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(0, draw_scale_rect.mBottom);
 
-			glTexCoord2f(border_width_fraction, border_height_fraction);
-			glVertex2i(scaled_border_width, scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(scaled_border_width, height - scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2f(0.f, 1.f - border_height_fraction);
-			glVertex2i(0, height - scaled_border_height);
+			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(0, draw_scale_rect.mTop);
 
 			// draw middle
-			glTexCoord2f(border_width_fraction, border_height_fraction);
-			glVertex2i(scaled_border_width, scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
 
-			glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
-			glVertex2i(width - scaled_border_width, scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(width - scaled_border_width, height - scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(scaled_border_width, height - scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
 			// draw right 
-			glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
-			glVertex2i(width - scaled_border_width, scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
 
-			glTexCoord2f(1.f, border_height_fraction);
-			glVertex2i(width, scaled_border_height);
+			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
+			glVertex2i(width, draw_scale_rect.mBottom);
 
-			glTexCoord2f(1.f, 1.f - border_height_fraction);
-			glVertex2i(width, height - scaled_border_height);
+			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(width, draw_scale_rect.mTop);
 
-			glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(width - scaled_border_width, height - scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
 			// draw top left
-			glTexCoord2f(0.f, 1.f - border_height_fraction);
-			glVertex2i(0, height - scaled_border_height);
+			glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(0, draw_scale_rect.mTop);
 
-			glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(scaled_border_width, height - scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2f(border_width_fraction, 1.f);
-			glVertex2i(scaled_border_width, height);
+			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, height);
 
-			glTexCoord2f(0.f, 1.f);
+			glTexCoord2d(uv_rect.mLeft, uv_rect.mTop);
 			glVertex2i(0, height);
 
 			// draw top middle
-			glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(scaled_border_width, height - scaled_border_height);
+			glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
 
-			glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(width - scaled_border_width, height - scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2f(1.f - border_width_fraction, 1.f);
-			glVertex2i(width - scaled_border_width, height);
+			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, height);
 
-			glTexCoord2f(border_width_fraction, 1.f);
-			glVertex2i(scaled_border_width, height);
+			glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+			glVertex2i(draw_scale_rect.mLeft, height);
 
 			// draw top right
-			glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
-			glVertex2i(width - scaled_border_width, height - scaled_border_height);
+			glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
 
-			glTexCoord2f(1.f, 1.f - border_height_fraction);
-			glVertex2i(width, height - scaled_border_height);
+			glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
+			glVertex2i(width, draw_scale_rect.mTop);
 
-			glTexCoord2f(1.f, 1.f);
+			glTexCoord2d(uv_rect.mRight, uv_rect.mTop);
 			glVertex2i(width, height);
 
-			glTexCoord2f(1.f - border_width_fraction, 1.f);
-			glVertex2i(width - scaled_border_width, height);
+			glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
+			glVertex2i(draw_scale_rect.mRight, height);
 		}
 		glEnd();
 	}
@@ -602,12 +636,12 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
 	}
 }
 
-void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color)
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
 {
-	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color );
+	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
 }
 
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
 {
 	if (NULL == image)
 	{
@@ -635,16 +669,16 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 		
 		glBegin(GL_QUADS);
 		{
-			glTexCoord2f(1.f, 1.f);
+			glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
 			glVertex2i(width, height );
 
-			glTexCoord2f(0.f, 1.f);
+			glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
 			glVertex2i(0, height );
 
-			glTexCoord2f(0.f, 0.f);
+			glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
 			glVertex2i(0, 0);
 
-			glTexCoord2f(1.f, 0.f);
+			glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
 			glVertex2i(width, 0);
 		}
 		glEnd();
@@ -653,7 +687,7 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 }
 
 
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
 {
 	if (NULL == image)
 	{
@@ -673,16 +707,16 @@ void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageG
 		
 		glBegin(GL_QUADS);
 		{
-			glTexCoord2f(1.f, 0.f);
+			glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
 			glVertex2i(width, height );
 
-			glTexCoord2f(0.f, 0.f);
+			glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
 			glVertex2i(0, height );
 
-			glTexCoord2f(0.f, 1.f);
+			glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
 			glVertex2i(0, 0);
 
-			glTexCoord2f(1.f, 1.f);
+			glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
 			glVertex2i(width, 0);
 		}
 		glEnd();
@@ -1584,40 +1618,6 @@ void LLUI::loadIdentity()
 	LLFontGL::sCurOrigin.mZ = 0;
 }
 
-//static 
-void LLUI::setScissorRegionScreen(const LLRect& rect)
-{
-	stop_glerror();
-	S32 x,y,w,h;
-	x = llround(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]);
-	y = llround(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]);
-	w = llround(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
-	h = llround(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
-	glScissor( x,y,w,h );
-	stop_glerror();
-}
-
-//static
-void LLUI::setScissorRegionLocal(const LLRect& rect)
-{
-	stop_glerror();
-	S32 screen_left = LLFontGL::sCurOrigin.mX + rect.mLeft;
-	S32 screen_bottom = LLFontGL::sCurOrigin.mY + rect.mBottom;
-	
-	S32 x,y,w,h;
-	
-	x = llround((F32)screen_left * LLUI::sGLScaleFactor.mV[VX]);
-	y = llround((F32)screen_bottom * LLUI::sGLScaleFactor.mV[VY]);
-	w = llround((F32)rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
-	h = llround((F32)rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
-	
-	w = llmax(0,w);
-	h = llmax(0,h);
-	
-	glScissor(x,y,w,h);
-	stop_glerror();
-}
-
 //static
 void LLUI::setScaleFactor(const LLVector2 &scale_factor)
 {
@@ -1738,64 +1738,169 @@ LLUUID			LLUI::findAssetUUIDByName(const LLString	&asset_name)
 	return LLUUID( foundValue );
 }
 
+//static 
+LLUIImage* LLUI::getUIImageByName(const LLString& name)
+{
+	return sImageProvider->getUIImageByID(findAssetUUIDByName(name));
+}
+
+
 // static 
 void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
 {
 	LLUI::sHtmlHelp = html_help;
 }
 
+LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST), mEnabled(enabled)
+{
+	if (mEnabled)
+	{
+		pushClipRect(rect);
+	}
+	mScissorState.setEnabled(!sClipRectStack.empty());
+	updateScissorRegion();
+}
+
+LLScreenClipRect::~LLScreenClipRect()
+{
+	if (mEnabled)
+	{
+		popClipRect();
+	}
+	updateScissorRegion();
+}
+
 //static 
-void LLUI::pushClipRect(const LLRect& rect)
+void LLScreenClipRect::pushClipRect(const LLRect& rect)
 {
 	LLRect combined_clip_rect = rect;
 	if (!sClipRectStack.empty())
 	{
-		combined_clip_rect.intersectWith(sClipRectStack.top());
+		LLRect top = sClipRectStack.top();
+		combined_clip_rect.intersectWith(top);
 	}
 	sClipRectStack.push(combined_clip_rect);
-	setScissorRegionScreen(combined_clip_rect);
 }
 
 //static 
-void LLUI::popClipRect()
+void LLScreenClipRect::popClipRect()
 {
 	sClipRectStack.pop();
-	if (!sClipRectStack.empty())
-	{
-		setScissorRegionScreen(sClipRectStack.top());
-	}
 }
 
-LLClipRect::LLClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
+//static
+void LLScreenClipRect::updateScissorRegion()
 {
-	if (mEnabled)
-	{
-		LLUI::pushClipRect(rect);
-	}
+	if (sClipRectStack.empty()) return;
+
+	LLRect rect = sClipRectStack.top();
+	stop_glerror();
+	S32 x,y,w,h;
+	x = llfloor(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]);
+	y = llfloor(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]);
+	w = llmax(0, llceil(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX])) + 1;
+	h = llmax(0, llceil(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY])) + 1;
+	glScissor( x,y,w,h );
+	stop_glerror();
 }
 
-LLClipRect::~LLClipRect()
+
+LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) 
+: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, 
+						rect.mTop + LLFontGL::sCurOrigin.mY, 
+						rect.mRight + LLFontGL::sCurOrigin.mX, 
+						rect.mBottom + LLFontGL::sCurOrigin.mY),
+					enabled)
 {
-	if (mEnabled)
-	{
-		LLUI::popClipRect();
-	}
 }
 
-LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
+
+//
+// LLUIImage
+//
+
+LLUIImage::LLUIImage(LLPointer<LLImageGL> image) :
+						mImage(image),
+						mScaleRegion(0.f, 1.f, 1.f, 0.f),
+						mClipRegion(0.f, 1.f, 1.f, 0.f),
+						mUniformScaling(TRUE),
+						mNoClip(TRUE)
+{
+}
+
+void LLUIImage::setClipRegion(const LLRectf& region) 
+{ 
+	mClipRegion = region; 
+	mNoClip = mClipRegion.mLeft == 0.f
+				&& mClipRegion.mRight == 1.f
+				&& mClipRegion.mBottom == 0.f
+				&& mClipRegion.mTop == 1.f;
+}
+
+void LLUIImage::setScaleRegion(const LLRectf& region) 
+{ 
+	mScaleRegion = region; 
+	mUniformScaling = mScaleRegion.mLeft == 0.f
+					&& mScaleRegion.mRight == 1.f
+					&& mScaleRegion.mBottom == 0.f
+					&& mScaleRegion.mTop == 1.f;
+}
+
+//TODO: move drawing implementation inside class
+void LLUIImage::draw(S32 x, S32 y, const LLColor4& color)
 {
-	if (mEnabled)
-	{
-		LLRect scissor_rect = rect;
-		scissor_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY);
-		LLUI::pushClipRect(scissor_rect);
-	}
+	gl_draw_image(x, y, mImage, color, mClipRegion);
 }
 
-LLLocalClipRect::~LLLocalClipRect()
+void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color)
 {
-	if (mEnabled)
+	if (mUniformScaling)
 	{
-		LLUI::popClipRect();
+		gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion);
 	}
+	else
+	{
+		gl_draw_scaled_image_with_border(
+			x, y, 
+			width, height, 
+			mImage, 
+			color,
+			FALSE,
+			mClipRegion,
+			mScaleRegion);
+	}
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color)
+{
+	gl_draw_scaled_image_with_border(
+		x, y, 
+		width, height, 
+		mImage, 
+		color, 
+		TRUE,
+		mClipRegion,
+		mScaleRegion);
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, const LLColor4& color)
+{
+	gl_draw_scaled_image_with_border(
+		x, y, 
+		getWidth(), getHeight(), 
+		mImage, 
+		color, 
+		TRUE,
+		mClipRegion,
+		mScaleRegion);
+}
+
+S32 LLUIImage::getWidth()
+{ 
+	return mImage->getWidth(0); 
+}
+
+S32 LLUIImage::getHeight()
+{ 
+	return mImage->getHeight(0); 
 }
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index b98f4d5de221a4f2efef98168f40c1cae1aa62aa..05982aa9e222e8ee16881a9ced64ee02c89c09ab 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -41,14 +41,15 @@
 #include "llhtmlhelp.h"
 #include "llgl.h"
 #include <stack>
+#include "llimagegl.h"
 
 class LLColor4;
 class LLVector3;
 class LLVector2;
-class LLImageGL;
 class LLUUID;
 class LLWindow;
 class LLView;
+class LLUIImage;
 
 // UI colors
 extern const LLColor4 UI_VERTEX_COLOR;
@@ -83,13 +84,14 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4&
 void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
 void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color);
 
-void gl_draw_image(S32 x, S32 y, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE);
+void gl_draw_image(S32 x, S32 y, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 // Flip vertical, used for LLFloaterHTML
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
+void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 
 void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom);
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); 
@@ -166,13 +168,12 @@ class LLUI
 
 	//helper functions (should probably move free standing rendering helper functions here)
 	static LLString locateSkin(const LLString& filename);
-	static void pushClipRect(const LLRect& rect);
-	static void popClipRect();
 	static void setCursorPositionScreen(S32 x, S32 y);
 	static void setCursorPositionLocal(LLView* viewp, S32 x, S32 y);
 	static void setScaleFactor(const LLVector2& scale_factor);
 	static void setLineWidth(F32 width);
 	static LLUUID findAssetUUIDByName(const LLString&	name);
+	static LLUIImage* getUIImageByName(const LLString& name);
 	static LLVector2 getWindowSize();
 	static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
 	static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
@@ -180,10 +181,6 @@ class LLUI
 	static void glRectToScreen(const LLRect& gl, LLRect *screen);
 	static void setHtmlHelp(LLHtmlHelp* html_help);
 
-private:
-	static void setScissorRegionScreen(const LLRect& rect);
-	static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called
-
 public:
 	static LLControlGroup* sConfigGroup;
 	static LLControlGroup* sColorsGroup;
@@ -194,7 +191,6 @@ class LLUI
 	static LLWindow*		sWindow;
 	static BOOL             sShowXUINames;
 	static LLHtmlHelp*		sHtmlHelp;
-	static std::stack<LLRect> sClipRectStack;
 
 };
 
@@ -286,6 +282,7 @@ typedef enum e_widget_type
 	WIDGET_TYPE_MEMORY_VIEW,
 	WIDGET_TYPE_FRAME_STAT_VIEW,
 	WIDGET_TYPE_LAYOUT_STACK,
+	WIDGET_TYPE_FLYOUT_BUTTON,
 	WIDGET_TYPE_DONTCARE,
 	WIDGET_TYPE_COUNT
 } EWidgetType;
@@ -382,24 +379,65 @@ class LLUISingleton: public LLUIInstanceMgr<T, INSTANCE_ADAPTOR>
 
 template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL;
 
-class LLClipRect
+class LLScreenClipRect
 {
 public:
-	LLClipRect(const LLRect& rect, BOOL enabled = TRUE);
-	virtual ~LLClipRect();
-protected:
+	LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
+	virtual ~LLScreenClipRect();
+
+private:
+	static void pushClipRect(const LLRect& rect);
+	static void popClipRect();
+	static void updateScissorRegion();
+
+private:
 	LLGLState		mScissorState;
 	BOOL			mEnabled;
+
+	static std::stack<LLRect> sClipRectStack;
 };
 
-class LLLocalClipRect
+class LLLocalClipRect : public LLScreenClipRect
 {
 public:
 	LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
-	virtual ~LLLocalClipRect();
+};
+
+class LLUIImage : public LLRefCount
+{
+public:
+	LLUIImage(LLPointer<LLImageGL> image);
+
+	void setClipRegion(const LLRectf& region);
+	void setScaleRegion(const LLRectf& region);
+
+	LLPointer<LLImageGL> getImage() { return mImage; }
+
+	void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR);
+	void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR);
+	void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color);
+	void drawSolid(S32 x, S32 y, const LLColor4& color);
+
+	S32 getWidth();
+	S32 getHeight();
+
 protected:
-	LLGLState		mScissorState;
-	BOOL			mEnabled;
+	LLRectf				mScaleRegion;
+	LLRectf				mClipRegion;
+	LLPointer<LLImageGL> mImage;
+	BOOL				mUniformScaling;
+	BOOL				mNoClip;
+};
+
+//RN: maybe this needs to moved elsewhere?
+class LLImageProviderInterface
+{
+public:
+	LLImageProviderInterface() {};
+	virtual ~LLImageProviderInterface() {};
+
+	virtual LLUIImage* getUIImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
+	virtual LLImageGL* getImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
 };
 
 #endif
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 7d354753d3cffcdea770ae0aeb95bcc8dee37ae4..8645f50764011f8b7a48b343874ef095f8969981 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -47,11 +47,53 @@
 
 const U32 MAX_STRING_LENGTH = 10;
 
-LLUICtrl::LLUICtrl() :
-	mCommitCallback(NULL),
-	mFocusLostCallback(NULL),
+LLFocusableElement::LLFocusableElement()
+:	mFocusLostCallback(NULL),
 	mFocusReceivedCallback(NULL),
 	mFocusChangedCallback(NULL),
+	mFocusCallbackUserData(NULL)
+{
+}
+
+void LLFocusableElement::onFocusReceived()
+{
+	if( mFocusReceivedCallback )
+	{
+		mFocusReceivedCallback( this, mFocusCallbackUserData );
+	}
+	if( mFocusChangedCallback )
+	{
+		mFocusChangedCallback( this, mFocusCallbackUserData );
+	}
+}
+
+void LLFocusableElement::onFocusLost()
+{
+	if( mFocusLostCallback )
+	{
+		mFocusLostCallback( this, mFocusCallbackUserData );
+	}
+
+	if( mFocusChangedCallback )
+	{
+		mFocusChangedCallback( this, mFocusCallbackUserData );
+	}
+}
+
+BOOL LLFocusableElement::hasFocus() const
+{
+	return FALSE;
+}
+
+void LLFocusableElement::setFocus(BOOL b)
+{
+}
+
+
+
+LLUICtrl::LLUICtrl() :
+	mCommitCallback(NULL),
+	mLostTopCallback(NULL),
 	mValidateCallback(NULL),
 	mCallbackUserData(NULL),
 	mTentative(FALSE),
@@ -68,9 +110,7 @@ LLUICtrl::LLUICtrl(const LLString& name, const LLRect& rect, BOOL mouse_opaque,
 	// of buttons in the UI. JC 7/20/2002
 	LLView( name, rect, mouse_opaque, reshape ),
 	mCommitCallback( on_commit_callback) ,
-	mFocusLostCallback( NULL ),
-	mFocusReceivedCallback( NULL ),
-	mFocusChangedCallback( NULL ),
+	mLostTopCallback( NULL ),
 	mValidateCallback( NULL ),
 	mCallbackUserData( callback_userdata ),
 	mTentative( FALSE ),
@@ -128,6 +168,86 @@ LLCtrlScrollInterface* LLUICtrl::getScrollInterface()
 	return NULL; 
 }
 
+BOOL LLUICtrl::hasFocus() const
+{
+	return (gFocusMgr.childHasKeyboardFocus(this));
+}
+
+void LLUICtrl::setFocus(BOOL b)
+{
+	// focus NEVER goes to ui ctrls that are disabled!
+	if (!mEnabled)
+	{
+		return;
+	}
+	if( b )
+	{
+		if (!hasFocus())
+		{
+			gFocusMgr.setKeyboardFocus( this );
+		}
+	}
+	else
+	{
+		if( gFocusMgr.childHasKeyboardFocus(this))
+		{
+			gFocusMgr.setKeyboardFocus( NULL );
+		}
+	}
+}
+
+void LLUICtrl::onFocusReceived()
+{
+	// trigger callbacks
+	LLFocusableElement::onFocusReceived();
+
+	// find first view in hierarchy above new focus that is a LLUICtrl
+	LLView* viewp = getParent();
+	LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus();
+
+	while (viewp && !viewp->isCtrl()) 
+	{
+		viewp = viewp->getParent();
+	}
+
+	// and if it has newly gained focus, call onFocusReceived()
+	LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
+	if (ctrlp && (!last_focus || !last_focus->hasAncestor(ctrlp)))
+	{
+		ctrlp->onFocusReceived();
+	}
+}
+
+void LLUICtrl::onFocusLost()
+{
+	// trigger callbacks
+	LLFocusableElement::onFocusLost();
+
+	// find first view in hierarchy above old focus that is a LLUICtrl
+	LLView* viewp = getParent();
+	while (viewp && !viewp->isCtrl()) 
+	{
+		viewp = viewp->getParent();
+	}
+
+	// and if it has just lost focus, call onFocusReceived()
+	LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
+	// hasFocus() includes any descendants
+	if (ctrlp && !ctrlp->hasFocus())
+	{
+		ctrlp->onFocusLost();
+	}
+}
+
+void LLUICtrl::onLostTop()
+{
+	if (mLostTopCallback)
+	{
+		mLostTopCallback(this, mCallbackUserData);
+	}
+}
+
+
 // virtual
 void LLUICtrl::setTabStop( BOOL b )	
 { 
@@ -168,67 +288,6 @@ BOOL LLUICtrl::getIsChrome() const
 	return mIsChrome; 
 }
 
-void LLUICtrl::onFocusReceived()
-{
-	if( mFocusReceivedCallback )
-	{
-		mFocusReceivedCallback( this, mCallbackUserData );
-	}
-	if( mFocusChangedCallback )
-	{
-		mFocusChangedCallback( this, mCallbackUserData );
-	}
-}
-
-void LLUICtrl::onFocusLost()
-{
-	if( mFocusLostCallback )
-	{
-		mFocusLostCallback( this, mCallbackUserData );
-	}
-
-	if( mFocusChangedCallback )
-	{
-		mFocusChangedCallback( this, mCallbackUserData );
-	}
-}
-
-BOOL LLUICtrl::hasFocus() const
-{
-	return (gFocusMgr.childHasKeyboardFocus(this));
-}
-
-void LLUICtrl::setFocus(BOOL b)
-{
-	// focus NEVER goes to ui ctrls that are disabled!
-	if (!mEnabled)
-	{
-		return;
-	}
-	if( b )
-	{
-		if (!hasFocus())
-		{
-			gFocusMgr.setKeyboardFocus( this, &LLUICtrl::onFocusLostCallback );
-			onFocusReceived();
-		}
-	}
-	else
-	{
-		if( gFocusMgr.childHasKeyboardFocus(this))
-		{
-			gFocusMgr.setKeyboardFocus( NULL, NULL );
-			onFocusLost();
-		}
-	}
-}
-
-// static
-void LLUICtrl::onFocusLostCallback( LLUICtrl* old_focus )
-{
-	old_focus->onFocusLost();
-}
-
 // this comparator uses the crazy disambiguating logic of LLCompareByTabOrder,
 // but to switch up the order so that children that have the default tab group come first
 // and those that are prior to the default tab group come last
@@ -262,6 +321,7 @@ class DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSingleton<Defa
 	}
 };
 
+
 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields)
 {
 	// try to select default tab group child
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 00f78748a75dbd38cb6a30e9c30f3082fee9d17a..ae360f401f4d9696c25d46b7fce093a3992d47d3 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -53,8 +53,31 @@ class LLCtrlScrollInterface;
 typedef void (*LLUICtrlCallback)(LLUICtrl* ctrl, void* userdata);
 typedef BOOL (*LLUICtrlValidate)(LLUICtrl* ctrl, void* userdata);
 
+class LLFocusableElement
+{
+	friend class LLFocusMgr; // allow access to focus change handlers
+public:
+	LLFocusableElement();
+	virtual ~LLFocusableElement() {};
+
+	virtual void	setFocus( BOOL b );
+	virtual BOOL	hasFocus() const;
+
+	void			setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; }
+	void			setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL)	{ mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; }
+	void			setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL )		{ mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; }
+
+protected:
+	virtual void	onFocusReceived();
+	virtual void	onFocusLost();
+	void			(*mFocusLostCallback)( LLFocusableElement* caller, void* userdata );
+	void			(*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata );
+	void			(*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata );
+	void*			mFocusCallbackUserData;
+};
+
 class LLUICtrl
-: public LLView
+: public LLView, public LLFocusableElement
 {
 public:
 	LLUICtrl();
@@ -85,6 +108,11 @@ class LLUICtrl
 	virtual void	setFocus( BOOL b );
 	virtual BOOL	hasFocus() const;
 
+	virtual void	onFocusReceived();
+	virtual void	onFocusLost();
+
+	virtual void	onLostTop();	// called when registered as top ctrl and user clicks elsewhere
+
 	virtual void	setTabStop( BOOL b );
 	virtual BOOL	hasTabStop() const;
 
@@ -115,6 +143,7 @@ class LLUICtrl
 	
 	void			setCommitCallback( void (*cb)(LLUICtrl*, void*) )		{ mCommitCallback = cb; }
 	void			setValidateBeforeCommit( BOOL(*cb)(LLUICtrl*, void*) )	{ mValidateCallback = cb; }
+	void			setLostTopCallback( void (*cb)(LLUICtrl*, void*) )		{ mLostTopCallback = cb; }
 
 	// Defaults to no-op!
 	virtual	void	setDoubleClickCallback( void (*cb)(void*) );
@@ -126,23 +155,8 @@ class LLUICtrl
 	virtual void	setMinValue(LLSD min_value);
 	virtual void	setMaxValue(LLSD max_value);
 
-	// In general, only LLPanel uses these.
-	void			setFocusLostCallback(void (*cb)(LLUICtrl* caller, void* user_data)) { mFocusLostCallback = cb; }
-	void			setFocusReceivedCallback( void (*cb)(LLUICtrl*, void*) )	{ mFocusReceivedCallback = cb; }
-	void			setFocusChangedCallback( void (*cb)(LLUICtrl*, void*) )		{ mFocusChangedCallback = cb; }
-
-	static void		onFocusLostCallback(LLUICtrl* old_focus);
-
 	/*virtual*/ BOOL focusFirstItem(BOOL prefer_text_fields = FALSE );
 
-	class LLTabStopPostFilter : public LLQueryFilter, public LLSingleton<LLTabStopPostFilter>
-	{
-		/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const 
-		{
-			return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->hasTabStop() && children.size() == 0, TRUE);
-		}
-	};
-
 	class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>
 	{
 		/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const 
@@ -156,17 +170,10 @@ class LLUICtrl
 	// Clear the dirty state
 	virtual void	resetDirty()			{};
 
-protected:
-	virtual void	onFocusReceived();
-	virtual void	onFocusLost();
-	void			onChangeFocus( S32 direction );
-
 protected:
 
 	void			(*mCommitCallback)( LLUICtrl* ctrl, void* userdata );
-	void			(*mFocusLostCallback)( LLUICtrl* caller, void* userdata );
-	void			(*mFocusReceivedCallback)( LLUICtrl* ctrl, void* userdata );
-	void			(*mFocusChangedCallback)( LLUICtrl* ctrl, void* userdata );
+	void			(*mLostTopCallback)( LLUICtrl* ctrl, void* userdata );
 	BOOL			(*mValidateCallback)( LLUICtrl* ctrl, void* userdata );
 
 	void*			mCallbackUserData;
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 88e4e89a2b729e858c04c7ec4c7323c513cb91c1..1e8798e7f7024687a8f41858fb554b3ac8d97278 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -173,7 +173,7 @@ std::vector<LLString> LLUICtrlFactory::mXUIPaths;
 class LLUICtrlLocate : public LLUICtrl
 {
 public:
-	LLUICtrlLocate() : LLUICtrl("locate", LLRect(0,0,0,0), FALSE, NULL, NULL) {}
+	LLUICtrlLocate() : LLUICtrl("locate", LLRect(0,0,0,0), FALSE, NULL, NULL) { setTabStop(FALSE); }
 	virtual void draw() { }
 
 	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LOCATE; }
@@ -181,7 +181,11 @@ class LLUICtrlLocate : public LLUICtrl
 
 	static LLView *fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
 	{
+		LLString name("pad");
+		node->getAttributeString("name", name);
+
 		LLUICtrlLocate *new_ctrl = new LLUICtrlLocate();
+		new_ctrl->setName(name);
 		new_ctrl->initFromXML(node, parent);
 		return new_ctrl;
 	}
@@ -196,6 +200,7 @@ LLUICtrlFactory::LLUICtrlFactory()
 	LLUICtrlCreator<LLButton>::registerCreator(LL_BUTTON_TAG, this);
 	LLUICtrlCreator<LLCheckBoxCtrl>::registerCreator(LL_CHECK_BOX_CTRL_TAG, this);
 	LLUICtrlCreator<LLComboBox>::registerCreator(LL_COMBO_BOX_TAG, this);
+	LLUICtrlCreator<LLFlyoutButton>::registerCreator(LL_FLYOUT_BUTTON_TAG, this);
 	LLUICtrlCreator<LLLineEditor>::registerCreator(LL_LINE_EDITOR_TAG, this);
 	LLUICtrlCreator<LLSearchEditor>::registerCreator(LL_SEARCH_EDITOR_TAG, this);
 	LLUICtrlCreator<LLScrollListCtrl>::registerCreator(LL_SCROLL_LIST_CTRL_TAG, this);
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a047f9912e8330ae23b347806bce5b7ba5374bb7..370288e949889d3165a7ed5823847a4ac4fc34d9 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -113,7 +113,7 @@ LLView::LLView() :
 	mSaveToXML(TRUE),
 	mIsFocusRoot(FALSE),
 	mLastVisible(TRUE),
-	mSpanChildren(FALSE),
+	mUseBoundingRect(FALSE),
 	mVisible(TRUE),
 	mHidden(FALSE),
 	mNextInsertionOrdinal(0)
@@ -133,7 +133,7 @@ LLView::LLView(const LLString& name, BOOL mouse_opaque) :
 	mSaveToXML(TRUE),
 	mIsFocusRoot(FALSE),
 	mLastVisible(TRUE),
-	mSpanChildren(FALSE),
+	mUseBoundingRect(FALSE),
 	mVisible(TRUE),
 	mHidden(FALSE),
 	mNextInsertionOrdinal(0)
@@ -148,6 +148,7 @@ LLView::LLView(
 	mParentView(NULL),
 	mName(name),
 	mRect(rect),
+	mBoundingRect(rect),
 	mReshapeFlags(reshape),
 	mDefaultTabGroup(0),
 	mEnabled(TRUE),
@@ -156,7 +157,7 @@ LLView::LLView(
 	mSaveToXML(TRUE),
 	mIsFocusRoot(FALSE),
 	mLastVisible(TRUE),
-	mSpanChildren(FALSE),
+	mUseBoundingRect(FALSE),
 	mVisible(TRUE),
 	mHidden(FALSE),
 	mNextInsertionOrdinal(0)
@@ -235,10 +236,16 @@ BOOL LLView::setToolTipArg(const LLStringExplicit& key, const LLStringExplicit&
 	return TRUE;
 }
 
+void LLView::setToolTipArgs( const LLString::format_map_t& args )
+{
+	mToolTipMsg.setArgList(args);
+}
+
 // virtual
 void LLView::setRect(const LLRect& rect)
 {
 	mRect = rect;
+	updateBoundingRect();
 }
 
 
@@ -287,9 +294,18 @@ void LLView::setName(LLString name)
 	mName = name;
 }
 
-void LLView::setSpanChildren( BOOL span_children ) 
+void LLView::setUseBoundingRect( BOOL use_bounding_rect ) 
+{
+	if (mUseBoundingRect != use_bounding_rect)
+	{
+        mUseBoundingRect = use_bounding_rect; 
+		updateBoundingRect();
+	}
+}
+
+BOOL LLView::getUseBoundingRect()
 {
-	mSpanChildren = span_children; updateRect();
+	return mUseBoundingRect;
 }
 
 const LLString& LLView::getToolTip()
@@ -306,7 +322,7 @@ const LLString& LLView::getName() const
 
 void LLView::sendChildToFront(LLView* child)
 {
-	if (child->mParentView == this) 
+	if (child && child->getParent() == this) 
 	{
 		mChildList.remove( child );
 		mChildList.push_front(child);
@@ -315,7 +331,7 @@ void LLView::sendChildToFront(LLView* child)
 
 void LLView::sendChildToBack(LLView* child)
 {
-	if (child->mParentView == this) 
+	if (child && child->getParent() == this) 
 	{
 		mChildList.remove( child );
 		mChildList.push_back(child);
@@ -330,6 +346,14 @@ void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child)
 	}
 }
 
+void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
+{
+	if(mCtrlOrder.find(child) != mCtrlOrder.end())
+	{
+		mCtrlOrder[child].second = mNextInsertionOrdinal++;
+	}
+}
+
 void LLView::addChild(LLView* child, S32 tab_group)
 {
 	if (mParentView == child) 
@@ -353,7 +377,7 @@ void LLView::addChild(LLView* child, S32 tab_group)
 	}
 
 	child->mParentView = this;
-	updateRect();
+	updateBoundingRect();
 }
 
 
@@ -380,7 +404,7 @@ void LLView::addChildAtEnd(LLView* child, S32 tab_group)
 	}
 	
 	child->mParentView = this;
-	updateRect();
+	updateBoundingRect();
 }
 
 // remove the specified child from the view, and set it's parent to NULL.
@@ -403,6 +427,7 @@ void LLView::removeChild(LLView* child, BOOL deleteIt)
 	{
 		llerrs << "LLView::removeChild called with non-child" << llendl;
 	}
+	updateBoundingRect();
 }
 
 void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
@@ -782,6 +807,7 @@ void LLView::setVisible(BOOL visible)
 			// tell all children of this view that the visibility may have changed
 			onVisibilityChange( visible );
 		}
+		updateBoundingRect();
 	}
 }
 
@@ -815,6 +841,7 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
 void LLView::translate(S32 x, S32 y)
 {
 	mRect.translate(x, y);
+	updateBoundingRect();
 }
 
 // virtual
@@ -831,7 +858,8 @@ void LLView::snappedTo(LLView* snap_view)
 BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = childrenHandleHover( x, y, mask ) != NULL;
-	if( !handled && mMouseOpaque && pointInView( x, y ) )
+	if( !handled 
+		&& blockMouseEvent(x, y) )
 	{
 		LLUI::sWindow->setCursor(UI_CURSOR_ARROW);
 		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
@@ -876,45 +904,46 @@ BOOL LLView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_scre
 
     LLString tool_tip;
 
-	if ( getVisible() && getEnabled())
+	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
 	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		LLView* viewp = *child_it;
+		S32 local_x = x - viewp->mRect.mLeft;
+		S32 local_y = y - viewp->mRect.mBottom;
+		if( viewp->pointInView(local_x, local_y) 
+			&& viewp->getVisible() 
+			&& viewp->getEnabled()
+			&& viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ))
 		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->mRect.mLeft;
-			S32 local_y = y - viewp->mRect.mBottom;
-			if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
-			{
-				handled = TRUE;
-				break;
-			}
+			handled = TRUE;
+			break;
 		}
+	}
 
-		tool_tip = mToolTipMsg.getString();
-		if (LLUI::sShowXUINames && (tool_tip.find(".xml", 0) == LLString::npos) && 
-			(mName.find("Drag", 0) == LLString::npos))
-		{
-			tool_tip = getShowNamesToolTip();
-		}
-		
+	tool_tip = mToolTipMsg.getString();
+	if (
+		LLUI::sShowXUINames &&
+		(tool_tip.find(".xml", 0) == LLString::npos) && 
+		(mName.find("Drag", 0) == LLString::npos))
+	{
+		tool_tip = getShowNamesToolTip();
+	}
 
-		BOOL showNamesTextBox = LLUI::sShowXUINames && (getWidgetType() == WIDGET_TYPE_TEXT_BOX);
+	BOOL showNamesTextBox = LLUI::sShowXUINames && (getWidgetType() == WIDGET_TYPE_TEXT_BOX);
 
-		if( !handled && (mMouseOpaque || showNamesTextBox) && pointInView( x, y ) && !tool_tip.empty())
-		{
+	if( !handled && (blockMouseEvent(x, y) || showNamesTextBox) && !tool_tip.empty())
+	{
 
-			msg = tool_tip;
+		msg = tool_tip;
 
-			// Convert rect local to screen coordinates
-			localPointToScreen(
-				0, 0,
-				&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
-			localPointToScreen(
-				mRect.getWidth(), mRect.getHeight(),
-				&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
-			
-			handled = TRUE;
-		}
+		// Convert rect local to screen coordinates
+		localPointToScreen(
+			0, 0,
+			&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+		localPointToScreen(
+			mRect.getWidth(), mRect.getHeight(),
+			&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+		
+		handled = TRUE;
 	}
 
 	return handled;
@@ -1025,7 +1054,7 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 											cargo_data,
 											accept,
 											tooltip_msg) != NULL;
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		*accept = ACCEPT_NO;
 		handled = TRUE;
@@ -1081,7 +1110,7 @@ BOOL LLView::hasMouseCapture()
 BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = childrenHandleMouseUp( x, y, mask ) != NULL;
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		handled = TRUE;
 	}
@@ -1092,7 +1121,7 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	LLView* handled_view = childrenHandleMouseDown( x, y, mask );
 	BOOL handled = (handled_view != NULL);
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		handled = TRUE;
 		handled_view = this;
@@ -1118,7 +1147,7 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		handleMouseDown(x, y, mask);
 		handled = TRUE;
@@ -1132,7 +1161,7 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	if( getVisible() && mEnabled )
 	{
 		handled = childrenHandleScrollWheel( x, y, clicks ) != NULL;
-		if( !handled && mMouseOpaque )
+		if( !handled && blockMouseEvent(x, y) )
 		{
 			handled = TRUE;
 		}
@@ -1143,7 +1172,7 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = childrenHandleRightMouseDown( x, y, mask ) != NULL;
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		handled = TRUE;
 	}
@@ -1153,7 +1182,7 @@ BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = childrenHandleRightMouseUp( x, y, mask ) != NULL;
-	if( !handled && mMouseOpaque )
+	if( !handled && blockMouseEvent(x, y) )
 	{
 		handled = TRUE;
 	}
@@ -1428,10 +1457,10 @@ void LLView::draw()
 		focus_view = NULL;
 	}
 
+	++sDepth;
 	for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
 	{
 		LLView *viewp = *child_iter;
-		++sDepth;
 
 		if (viewp->getVisible() && viewp != focus_view)
 		{
@@ -1449,8 +1478,8 @@ void LLView::draw()
 			}
 		}
 
-		--sDepth;
 	}
+	--sDepth;
 
 	if (focus_view && focus_view->getVisible())
 	{
@@ -1467,50 +1496,61 @@ void LLView::draw()
 //Draw a box for debugging.
 void LLView::drawDebugRect()
 {
-	// drawing solids requires texturing be disabled
-	LLGLSNoTexture no_texture;
-
-	// draw red rectangle for the border
-	LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
-	if (sEditingUI)
+	LLUI::pushMatrix();
 	{
-		border_color.mV[0] = 1.f;
-	}
-	else
-	{
-		border_color.mV[sDepth%3] = 1.f;
-	}
+		// drawing solids requires texturing be disabled
+		LLGLSNoTexture no_texture;
 
-	glColor4fv( border_color.mV );
+		if (mUseBoundingRect)
+		{
+			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);
+		}
 
-	glBegin(GL_LINES);
-		glVertex2i(0, mRect.getHeight() - 1);
-		glVertex2i(0, 0);
+		LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
 
-		glVertex2i(0, 0);
-		glVertex2i(mRect.getWidth() - 1, 0);
+		// draw red rectangle for the border
+		LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
+		if (sEditingUI)
+		{
+			border_color.mV[0] = 1.f;
+		}
+		else
+		{
+			border_color.mV[sDepth%3] = 1.f;
+		}
 
-		glVertex2i(mRect.getWidth() - 1, 0);
-		glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
+		glColor4fv( border_color.mV );
 
-		glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
-		glVertex2i(0, mRect.getHeight() - 1);
-	glEnd();
+		glBegin(GL_LINES);
+			glVertex2i(0, debug_rect.getHeight() - 1);
+			glVertex2i(0, 0);
 
-	// Draw the name if it's not a leaf node
-	if (mChildList.size() && !sEditingUI)
-	{
-		//char temp[256];
-		S32 x, y;
-		glColor4fv( border_color.mV );
-		x = mRect.getWidth()/2;
-		y = mRect.getHeight()/2;
-		LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
-									   mRect.getWidth(), mRect.getHeight());
-		LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
-											  LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
-											  S32_MAX, S32_MAX, NULL, FALSE);
+			glVertex2i(0, 0);
+			glVertex2i(debug_rect.getWidth() - 1, 0);
+
+			glVertex2i(debug_rect.getWidth() - 1, 0);
+			glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+
+			glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+			glVertex2i(0, debug_rect.getHeight() - 1);
+		glEnd();
+
+		// Draw the name if it's not a leaf node
+		if (mChildList.size() && !sEditingUI)
+		{
+			//char temp[256];
+			S32 x, y;
+			glColor4fv( border_color.mV );
+			x = debug_rect.getWidth()/2;
+			y = debug_rect.getHeight()/2;
+			LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
+										debug_rect.getWidth(), debug_rect.getHeight());
+			LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
+												LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
+												S32_MAX, S32_MAX, NULL, FALSE);
+		}
 	}
+	LLUI::popMatrix();
 }
 
 void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw)
@@ -1537,9 +1577,6 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr
 
 void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
-	// make sure this view contains all its children
-	updateRect();
-
 	// compute how much things changed and apply reshape logic to children
 	S32 delta_width = width - mRect.getWidth();
 	S32 delta_height = height - mRect.getHeight();
@@ -1608,6 +1645,8 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
 			mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE);
 		}
 	}
+
+	updateBoundingRect();
 }
 
 LLRect LLView::getRequiredRect()
@@ -1615,6 +1654,53 @@ LLRect LLView::getRequiredRect()
 	return mRect;
 }
 
+void LLView::updateBoundingRect()
+{
+	if (isDead()) return;
+
+	if (mUseBoundingRect)
+	{
+		LLRect local_bounding_rect = LLRect::null;
+
+		child_list_const_iter_t child_it;
+		for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		{
+			LLView* childp = *child_it;
+			if (!childp->getVisible()) continue;
+
+			LLRect child_bounding_rect = childp->getBoundingRect();
+
+			if (local_bounding_rect.isNull())
+			{
+				// start out with bounding rect equal to first visible child's bounding rect
+				local_bounding_rect = child_bounding_rect;
+			}
+			else
+			{
+				// accumulate non-null children rectangles
+				if (!child_bounding_rect.isNull())
+				{
+					local_bounding_rect.unionWith(child_bounding_rect);
+				}
+			}
+		}
+
+		mBoundingRect = local_bounding_rect;
+		// translate into parent-relative coordinates
+		mBoundingRect.translate(mRect.mLeft, mRect.mBottom);
+	}
+	else
+	{
+		mBoundingRect = mRect;
+	}
+
+	// give parent view a chance to resize, in case we just moved, for example
+	if (getParent() && getParent()->mUseBoundingRect)
+	{
+		getParent()->updateBoundingRect();
+	}
+}
+
 const LLRect LLView::getScreenRect() const
 {
 	// *FIX: check for one-off error
@@ -1624,6 +1710,15 @@ const LLRect LLView::getScreenRect() const
 	return screen_rect;
 }
 
+const LLRect LLView::getLocalBoundingRect() const
+{
+	LLRect local_bounding_rect = getBoundingRect();
+	local_bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
+
+	return local_bounding_rect;
+}
+
+
 const LLRect LLView::getLocalRect() const
 {
 	LLRect local_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
@@ -1637,38 +1732,7 @@ const LLRect LLView::getLocalSnapRect() const
 	return local_snap_rect;
 }
 
-void LLView::updateRect()
-{
-	if (mSpanChildren && mChildList.size())
-	{
-		LLView* first_child = (*mChildList.begin());
-		LLRect child_spanning_rect = first_child->mRect;
-
-		for ( child_list_iter_t child_it = ++mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			if (viewp->getVisible())
-			{
-				child_spanning_rect.unionWith(viewp->mRect);
-			}
-		}
-
-		S32 translate_x = llmin(0, child_spanning_rect.mLeft);
-		S32 translate_y = llmin(0, child_spanning_rect.mBottom);
-		S32 new_width	= llmax(mRect.getWidth() + translate_x, child_spanning_rect.getWidth());
-		S32 new_height	= llmax(mRect.getHeight() + translate_y, child_spanning_rect.getHeight());
-
-		mRect.setOriginAndSize(mRect.mLeft + translate_x, mRect.mBottom + translate_y, new_width, new_height);
-
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			viewp->mRect.translate(-translate_x, -translate_y);
-		}
-	}
-}
-
-BOOL LLView::hasAncestor(LLView* parentp)
+BOOL LLView::hasAncestor(const LLView* parentp)
 {
 	if (!parentp)
 	{
@@ -1743,14 +1807,23 @@ LLView* LLView::getChildByName(const LLString& name, BOOL recurse) const
 	return NULL;
 }
 
-// virtual
-void LLView::onFocusLost()
-{
+BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const 
+{ 
+	return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+		? mBoundingRect.pointInRect( x, y ) 
+		: mRect.pointInRect( x, y ); 
 }
 
-// virtual
-void LLView::onFocusReceived()
+BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const 
+{ 
+	return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+		? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom ) 
+		: mRect.localPointInRect( x, y ); 
+}
+
+BOOL LLView::blockMouseEvent(S32 x, S32 y) const
 {
+	return mMouseOpaque && pointInView(x, y, HIT_TEST_IGNORE_BOUNDING_RECT);
 }
 
 // virtual
@@ -2024,9 +2097,9 @@ LLXMLNodePtr LLView::getXML(bool save_children) const
 	// Export all widgets as enabled and visible - code must disable.
 	node->createChild("hidden", TRUE)->setBoolValue(mHidden);
 	node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque );
-	if (!mToolTipMsg.empty())
+	if (!mToolTipMsg.getString().empty())
 	{
-		node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg);
+		node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString());
 	}
 	if (mSoundFlags != MOUSE_UP)
 	{
@@ -2116,7 +2189,7 @@ const LLCtrlQuery & LLView::getTabOrderQuery()
 		query.addPreFilter(LLVisibleFilter::getInstance());
 		query.addPreFilter(LLEnabledFilter::getInstance());
 		query.addPreFilter(LLTabStopFilter::getInstance());
-		query.addPostFilter(LLUICtrl::LLTabStopPostFilter::getInstance());
+		query.addPostFilter(LLLeavesFilter::getInstance());
 	}
 	return query;
 }
@@ -2129,6 +2202,7 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
 		query.addPreFilter(LLVisibleFilter::getInstance());
 		query.addPreFilter(LLEnabledFilter::getInstance());
 		query.addPreFilter(LLView::LLFocusRootsFilter::getInstance());
+		query.addPostFilter(LLRootsFilter::getInstance());
 	}
 	return query;
 }
@@ -2593,10 +2667,10 @@ const S32 VPAD = 4;
 U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
 {
 	U32 follows = 0;
-	S32 x = FLOATER_H_MARGIN;
-	S32 y = 0;
-	S32 w = 0;
-	S32 h = 0;
+	S32 x = rect.mLeft;
+	S32 y = rect.mBottom;
+	S32 w = rect.getWidth();
+	S32 h = rect.getHeight();
 
 	U32 last_x = 0;
 	U32 last_y = 0;
@@ -2639,8 +2713,15 @@ U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, con
 	// view if you don't specify a width.
 	if (parent_view)
 	{
-		w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
-		h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+		if(w == 0)
+		{
+			w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
+		}
+
+		if(h == 0)
+		{
+			h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+		}
 	}
 
 	if (node->hasAttribute("width"))
@@ -2765,44 +2846,7 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
 	setRect(view_rect);
 	setFollows(follows_flags);
 
-	if (node->hasAttribute("follows"))
-	{
-		setFollowsNone();
-
-		LLString follows;
-		node->getAttributeString("follows", follows);
-
-		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-		boost::char_separator<char> sep("|");
-		tokenizer tokens(follows, sep);
-		tokenizer::iterator token_iter = tokens.begin();
-
-		while(token_iter != tokens.end())
-		{
-			const std::string& token_str = *token_iter;
-			if (token_str == "left")
-			{
-				setFollowsLeft();
-			}
-			else if (token_str == "right")
-			{
-				setFollowsRight();
-			}
-			else if (token_str == "top")
-			{
-				setFollowsTop();
-			}
-			else if (token_str == "bottom")
-			{
-				setFollowsBottom();
-			}
-			else if (token_str == "all")
-			{
-				setFollowsAll();
-			}
-			++token_iter;
-		}
-	}
+	parseFollowsFlags(node);
 
 	if (node->hasAttribute("control_name"))
 	{
@@ -2839,11 +2883,57 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
 		setHidden(hidden);
 	}
 
+	node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
+	node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
+
 	node->getAttributeS32("default_tab_group", mDefaultTabGroup);
 	
 	reshape(view_rect.getWidth(), view_rect.getHeight());
 }
 
+void LLView::parseFollowsFlags(LLXMLNodePtr node)
+{
+	if (node->hasAttribute("follows"))
+	{
+		setFollowsNone();
+
+		LLString follows;
+		node->getAttributeString("follows", follows);
+
+		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+		boost::char_separator<char> sep("|");
+		tokenizer tokens(follows, sep);
+		tokenizer::iterator token_iter = tokens.begin();
+
+		while(token_iter != tokens.end())
+		{
+			const std::string& token_str = *token_iter;
+			if (token_str == "left")
+			{
+				setFollowsLeft();
+			}
+			else if (token_str == "right")
+			{
+				setFollowsRight();
+			}
+			else if (token_str == "top")
+			{
+				setFollowsTop();
+			}
+			else if (token_str == "bottom")
+			{
+				setFollowsBottom();
+			}
+			else if (token_str == "all")
+			{
+				setFollowsAll();
+			}
+			++token_iter;
+		}
+	}
+}
+
+
 // static
 LLFontGL* LLView::selectFont(LLXMLNodePtr node)
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 8248d50d9d59c6d31628fd4b72bf66b167811121..e54983d67da1d09cb3377ef47669af9b6a7d231c 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -50,6 +50,7 @@
 #include "llviewquery.h"
 #include "llxmlnode.h"
 #include "stdenums.h"
+#include "lluistring.h"
 
 class LLColor4;
 class LLWindow;
@@ -146,6 +147,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	LLString	mName;
 	// location in pixels, relative to surrounding structure, bottom,left=0,0
 	LLRect		mRect;
+	LLRect		mBoundingRect;
 	
 	U32			mReshapeFlags;
 
@@ -161,11 +163,11 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	BOOL		mSaveToXML;
 
 	BOOL		mIsFocusRoot;
+	BOOL		mUseBoundingRect; // hit test against bounding rectangle that includes all child elements
 
 public:
 	LLViewHandle mViewHandle;
 	BOOL		mLastVisible;
-	BOOL		mSpanChildren;
 
 private:
 	BOOL		mVisible;
@@ -217,6 +219,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	void		setMouseOpaque( BOOL b );
 	void		setToolTip( const LLStringExplicit& msg );
 	BOOL		setToolTipArg( const LLStringExplicit& key, const LLStringExplicit& text );
+	void		setToolTipArgs( const LLString::format_map_t& args );
 
 	virtual void setRect(const LLRect &rect);
 	void		setFollows(U32 flags);
@@ -231,13 +234,15 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 
 	void        setSoundFlags(U8 flags);
 	void		setName(LLString name);
-	void		setSpanChildren( BOOL span_children );
+	void		setUseBoundingRect( BOOL use_bounding_rect );
+	BOOL		getUseBoundingRect();
 
 	const LLString& getToolTip();
 
 	void		sendChildToFront(LLView* child);
 	void		sendChildToBack(LLView* child);
 	void		moveChildToFrontOfTabGroup(LLUICtrl* child);
+	void		moveChildToBackOfTabGroup(LLUICtrl* child);
 
 	void		addChild(LLView* view, S32 tab_group = 0);
 	void		addChildAtEnd(LLView* view,  S32 tab_group = 0);
@@ -264,7 +269,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	{
 		/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const 
 		{
-			return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot());
+			return filterResult_t(view->isCtrl() && view->isFocusRoot(), TRUE);
 		}
 	};
 
@@ -312,20 +317,22 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	BOOL		followsAll() const				{ return mReshapeFlags & FOLLOWS_ALL; }
 
 	const LLRect&	getRect() const				{ return mRect; }
+	const LLRect&	getBoundingRect() const		{ return mBoundingRect; }
+	const LLRect	getLocalBoundingRect() const;
 	const LLRect	getScreenRect() const;
 	const LLRect	getLocalRect() const;
 	virtual const LLRect getSnapRect() const	{ return mRect; }
 	virtual const LLRect getLocalSnapRect() const;
 
 	virtual LLRect getRequiredRect();		// Get required size for this object. 0 for width/height means don't care.
-	virtual void updateRect();				// apply procedural updates to own rectangle
+	void updateBoundingRect();
 
 	LLView*		getRootView();
 	LLView*		getParent() const				{ return mParentView; }
 	LLView*		getFirstChild() 				{ return (mChildList.empty()) ? NULL : *(mChildList.begin()); }
 	S32			getChildCount()	const			{ return (S32)mChildList.size(); }
 	template<class _Pr3> void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); }
-	BOOL		hasAncestor(LLView* parentp);
+	BOOL		hasAncestor(const LLView* parentp);
 
 	BOOL		hasChild(const LLString& childname, BOOL recurse = FALSE) const;
 
@@ -390,6 +397,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 
 	static U32 createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect = LLRect());
 	virtual void initFromXML(LLXMLNodePtr node, LLView* parent);
+	void parseFollowsFlags(LLXMLNodePtr node);
 
 	static LLFontGL* selectFont(LLXMLNodePtr node);
 	static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node);
@@ -428,12 +436,16 @@ class LLView : public LLMouseHandler, public LLMortician, public LLSimpleListene
 	BOOL			getVisible() const			{ return mVisible && !mHidden; }
 	U8              getSoundFlags() const       { return mSoundFlags; }
 
-	// Default to no action
-	virtual void	onFocusLost();
-	virtual void	onFocusReceived();
+	typedef enum e_hit_test_type
+	{
+		HIT_TEST_USE_BOUNDING_RECT,
+		HIT_TEST_IGNORE_BOUNDING_RECT
+	}EHitTestType;
+
+	BOOL			parentPointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const;
+	BOOL			pointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const;
+	BOOL			blockMouseEvent(S32 x, S32 y) const;
 
-	BOOL			parentPointInView(S32 x, S32 y) const { return mRect.pointInRect( x, y ); }
-	BOOL			pointInView(S32 x, S32 y) const { return mRect.localPointInRect( x, y ); }
 	virtual void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
 	virtual void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
 	virtual BOOL	localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view);
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index f6cbe3aac103ecf882b469a7370ff36bacb8d5b9..8fbe67161363966353069005575eebf0f7108c18 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -84,7 +84,7 @@ void LLViewBorder::setColorsExtended( const LLColor4& shadow_light, const LLColo
 
 void LLViewBorder::setTexture( const LLUUID &image_id )
 {
-	mTexture = LLUI::sImageProvider->getUIImageByID(image_id);
+	mTexture = LLUI::sImageProvider->getImageByID(image_id);
 }
 
 
diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp
index c07587f0ff58f117601945f990b60df89d671b60..db00c7682172cf214096ec22448ba9acdf5aa2dd 100644
--- a/indra/llui/llviewquery.cpp
+++ b/indra/llui/llviewquery.cpp
@@ -37,9 +37,14 @@
 
 void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {}
 
-filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const 
+filterResult_t LLLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const 
 {
-	return filterResult_t(!(view->getChildList()->size() == 0), TRUE);
+	return filterResult_t(children.empty(), TRUE);
+}
+
+filterResult_t LLRootsFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(TRUE, FALSE);
 }
 
 filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const 
@@ -56,6 +61,16 @@ filterResult_t LLTabStopFilter::operator() (const LLView* const view, const view
 						view->canFocusChildren());
 }
 
+filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewList_t & children) const 
+{
+	return filterResult_t(view->isCtrl(),TRUE);
+}
+
+filterResult_t LLWidgetTypeFilter::operator() (const LLView* const view, const viewList_t & children) const
+{
+	return filterResult_t(view->getWidgetType() == mType, TRUE);
+} 
+
 // LLViewQuery
 
 LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp() 
@@ -73,45 +88,53 @@ const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return m
 void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; }
 const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; }
 
-viewList_t LLViewQuery::run(LLView * view) const
+viewList_t LLViewQuery::run(LLView* view) const
 {
 	viewList_t result;
 
-	filterResult_t pre = runFilters(view, viewList_t(), mPreFilters);
+	// prefilter gets immediate children of view
+	filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters);
 	if(!pre.first && !pre.second)
 	{
-		// skip post filters completely if we're not including ourselves or the children
+		// not including ourselves or the children
+		// nothing more to do
 		return result;
 	}
+
+	viewList_t filtered_children;
+	filterResult_t post(TRUE, TRUE);
 	if(pre.second)
 	{
 		// run filters on children
-		viewList_t filtered_children;
 		filterChildren(view, filtered_children);
-		filterResult_t post = runFilters(view, filtered_children, mPostFilters);
-		if(pre.first && post.first)
-		{
-			result.push_back(view);
-		}
-		if(post.second)
+		// only run post filters if this element passed pre filters
+		// so if you failed to pass the pre filter, you can't filter out children in post
+		if (pre.first)
 		{
-			result.insert(result.end(), filtered_children.begin(), filtered_children.end());
+			post = runFilters(view, filtered_children, mPostFilters);
 		}
 	}
-	else 
+
+	if(pre.first && post.first) 
 	{
-		if(pre.first) 
-		{
-			result.push_back(view);
-		}
+		result.push_back(view);
+	}
+
+	if(pre.second && post.second)
+	{
+		result.insert(result.end(), filtered_children.begin(), filtered_children.end());
 	}
+
 	return result;
 }
 
 void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const
 {
 	LLView::child_list_t views(*(view->getChildList()));
-	(*mSorterp)(view, views); // sort the children per the sorter
+	if (mSorterp)
+	{
+		(*mSorterp)(view, views); // sort the children per the sorter
+	}
 	for(LLView::child_list_iter_t iter = views.begin();
 			iter != views.end();
 			iter++)
diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h
index 3919ba4bcb8edbb3b0542d6be15a38031cbacd0c..63559e8240a5ad2d31512efe2a882180710ef7b7 100644
--- a/indra/llui/llviewquery.h
+++ b/indra/llui/llviewquery.h
@@ -35,6 +35,7 @@
 #include <list>	
 
 #include "llmemory.h"
+#include "llui.h"
 
 class LLView;
 
@@ -42,35 +43,60 @@ typedef std::list<LLView *>			viewList_t;
 typedef std::pair<BOOL, BOOL>		filterResult_t;
 
 // Abstract base class for all filters.
-class LLQueryFilter : public LLRefCount
+class LLQueryFilter
 {
 public:
+	virtual ~LLQueryFilter() {};
 	virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0;
 };
 
-class LLQuerySorter : public LLRefCount
+class LLQuerySorter
 {
 public:
+	virtual ~LLQuerySorter() {};
 	virtual void operator() (LLView * parent, viewList_t &children) const;
 };
 
-class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton<LLNoLeavesFilter>
+class LLLeavesFilter : public LLQueryFilter, public LLSingleton<LLLeavesFilter>
 {
 	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
 };
+
+class LLRootsFilter : public LLQueryFilter, public LLSingleton<LLRootsFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+
 class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
 {
 	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
 };
+
 class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
 {
 	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
 };
+
 class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
 {
 	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
 };
 
+class LLCtrlFilter : public LLQueryFilter, public LLSingleton<LLCtrlFilter>
+{
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+
+class LLWidgetTypeFilter : public LLQueryFilter
+{
+public:
+	LLWidgetTypeFilter(EWidgetType type) : mType(type) {};
+private:
+	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+
+	EWidgetType mType;
+};
+
 // Algorithm for flattening
 class LLViewQuery
 {
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 5aaf9d00973571c5fba0ae3a2a927cb24891f4bc..a692ef6a3e8d43a800510f7e69b16ae3e28c176b 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2880,7 +2880,7 @@ void LLAgent::endAnimationUpdateUI()
 		mCameraLag.clearVec();
 
 		// JC - Added for always chat in third person option
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
+		gFocusMgr.setKeyboardFocus(NULL);
 
 		gToolMgr->setCurrentToolset(gMouselookToolset);
 
@@ -4004,7 +4004,7 @@ void LLAgent::changeCameraToMouselook(BOOL animate)
 
 	if( mCameraMode != CAMERA_MODE_MOUSELOOK )
 	{
-		gViewerWindow->setKeyboardFocus( NULL, NULL );
+		gViewerWindow->setKeyboardFocus( NULL );
 		
 		mLastCameraMode = mCameraMode;
 		mCameraMode = CAMERA_MODE_MOUSELOOK;
@@ -4225,7 +4225,7 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL animate)
 			mbFlagsDirty = TRUE;
 		}
 
-		gViewerWindow->setKeyboardFocus( NULL, NULL );
+		gViewerWindow->setKeyboardFocus( NULL );
 		gViewerWindow->setMouseCapture( NULL );
 
 		LLVOAvatar::onCustomizeStart();
@@ -5225,6 +5225,102 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **)
 	}
 }
 
+class LLAgentDropGroupViewerNode : public LLHTTPNode
+{
+	virtual void post(
+		LLHTTPNode::ResponsePtr response,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+
+		if (
+			!input.isMap() ||
+			!input.has("body") )
+		{
+			//what to do with badly formed message?
+			response->status(400);
+			response->result(LLSD("Invalid message parameters"));
+		}
+
+		LLSD body = input["body"];
+		if ( body.has("body") ) 
+		{
+			//stupid message system doubles up the "body"s
+			body = body["body"];
+		}
+
+		if (
+			body.has("AgentData") &&
+			body["AgentData"].isArray() &&
+			body["AgentData"][0].isMap() )
+		{
+			llinfos << "VALID DROP GROUP" << llendl;
+
+			//there is only one set of data in the AgentData block
+			LLSD agent_data = body["AgentData"][0];
+			LLUUID agent_id;
+			LLUUID group_id;
+
+			agent_id = agent_data["AgentID"].asUUID();
+			group_id = agent_data["GroupID"].asUUID();
+
+			if (agent_id != gAgentID)
+			{
+				llwarns
+					<< "AgentDropGroup for agent other than me" << llendl;
+
+				response->notFound();
+				return;
+			}
+
+			// Remove the group if it already exists remove it
+			// and add the new data to pick up changes.
+			LLGroupData gd;
+			gd.mID = group_id;
+			S32 index = gAgent.mGroups.find(gd);
+			if (index != -1)
+			{
+				gAgent.mGroups.remove(index);
+				if (gAgent.getGroupID() == group_id)
+				{
+					gAgent.mGroupID.setNull();
+					gAgent.mGroupPowers = 0;
+					gAgent.mGroupName[0] = '\0';
+					gAgent.mGroupTitle[0] = '\0';
+				}
+		
+				// refresh all group information
+				gAgent.sendAgentDataUpdateRequest();
+
+				gGroupMgr->clearGroupData(group_id);
+				// close the floater for this group, if any.
+				LLFloaterGroupInfo::closeGroup(group_id);
+				// refresh the group panel of the search window,
+				//if necessary.
+				LLFloaterDirectory::refreshGroup(group_id);
+			}
+			else
+			{
+				llwarns
+					<< "AgentDropGroup, agent is not part of group "
+					<< group_id << llendl;
+			}
+
+			response->result(LLSD());
+		}
+		else
+		{
+			//what to do with badly formed message?
+			response->status(400);
+			response->result(LLSD("Invalid message parameters"));
+		}
+	}
+};
+
+LLHTTPRegistration<LLAgentDropGroupViewerNode>
+	gHTTPRegistrationAgentDropGroupViewerNode(
+		"/message/AgentDropGroup");
+
 // static
 void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **)
 {
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ad934abfa75a07598c8ec55525385ee365193868..8b126b7597bbe583755831d9c2fb7cc3e1859c88 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -425,7 +425,7 @@ static void ui_audio_callback(const LLUUID& uuid)
 {
 	if (gAudiop)
 	{
-		F32 volume = gSavedSettings.getF32("AudioLevelUI");
+		F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
 		gAudiop->triggerSound(uuid, gAgent.getID(), volume);
 	}
 }
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index c3c892a572292fef5d0d3488246259259d930f5c..76cfe92c4c5db674ecb6bf77400d83f15cdf8bce 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -252,7 +252,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 		if(view)
 		{
 			LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
-			LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();
 
 			view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO);
 			if((LLAssetType::AT_TEXTURE == asset_type)
@@ -262,7 +261,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 			}
 			//LLInventoryView::dumpSelectionInformation((void*)view);
 			// restore keyboard focus
-			gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
+			gFocusMgr.setKeyboardFocus(focus_ctrl);
 		}
 	}
 	else
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 3517c1e18a08a6a5a10897d0f8b0f66deed4226f..78365e66f185dd0a90b566a02315ced35fc0e18f 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -93,51 +93,20 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver
 // Functions
 //
 
-//inline constructor
-// for chat bars embedded in floaters, etc
-LLChatBar::LLChatBar(const std::string& name) 
-:	LLPanel(name, LLRect(), BORDER_NO),
+LLChatBar::LLChatBar() 
+:	LLPanel("", LLRect(), BORDER_NO),
 	mInputEditor(NULL),
 	mGestureLabelTimer(),
 	mLastSpecialChatChannel(0),
 	mIsBuilt(FALSE),
-	mDynamicLayout(FALSE),
-	mGestureCombo(NULL),
-	mObserver(NULL)
-{
-}
-
-LLChatBar::LLChatBar(const std::string& name, const LLRect& rect) 
-:	LLPanel(name, rect, BORDER_NO),
-	mInputEditor(NULL),
-	mGestureLabelTimer(),
-	mLastSpecialChatChannel(0),
-	mIsBuilt(FALSE),
-	mDynamicLayout(TRUE),
 	mGestureCombo(NULL),
 	mObserver(NULL)
 {
 	setIsChrome(TRUE);
 	
-	gUICtrlFactory->buildPanel(this,"panel_chat_bar.xml");
-	
-	mIsFocusRoot = TRUE;
-
-	setRect(rect); // override xml rect
-	
-	setBackgroundOpaque(TRUE);
-	setBackgroundVisible(TRUE);
-
-	// Start visible if we left the app while chatting.
-	setVisible( gSavedSettings.getBOOL("ChatVisible") );
-
-	// Apply custom layout.
-	layout();
-
-#if !LL_RELEASE_FOR_DOWNLOAD
+	#if !LL_RELEASE_FOR_DOWNLOAD
 	childDisplayNotFound();
 #endif
-	
 }
 
 
@@ -151,25 +120,18 @@ LLChatBar::~LLChatBar()
 BOOL LLChatBar::postBuild()
 {
 	childSetAction("History", toggleChatHistory, this);
-	childSetAction("Say", onClickSay, this);
-	childSetAction("Shout", onClickShout, this);
+	childSetCommitCallback("Say", onClickSay, this);
 
 	// attempt to bind to an existing combo box named gesture
 	setGestureCombo(LLUICtrlFactory::getComboBoxByName(this, "Gesture"));
 
-	LLButton * sayp = static_cast<LLButton*>(getChildByName("Say", TRUE));
-	if(sayp)
-	{
-		setDefaultBtn(sayp);
-	}
-
 	mInputEditor = LLUICtrlFactory::getLineEditorByName(this, "Chat Editor");
 	if (mInputEditor)
 	{
 		mInputEditor->setCallbackUserData(this);
 		mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke);
-		mInputEditor->setFocusLostCallback(&onInputEditorFocusLost);
-		mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus );
+		mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this);
+		mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this );
 		mInputEditor->setCommitOnFocusLost( FALSE );
 		mInputEditor->setRevertOnEsc( FALSE );
 		mInputEditor->setIgnoreTab(TRUE);
@@ -188,16 +150,6 @@ BOOL LLChatBar::postBuild()
 // Overrides
 //-----------------------------------------------------------------------
 
-// virtual
-void LLChatBar::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLPanel::reshape(width, height, called_from_parent);
-	if (mIsBuilt)
-	{
-		layout();
-	}
-}
-
 // virtual
 BOOL LLChatBar::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 {
@@ -208,13 +160,6 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 		// ALT-RETURN is reserved for windowed/fullscreen toggle
 		if( KEY_RETURN == key )
 		{
-			//if (childGetValue("Chat Editor").asString().empty())
-			//{
-			//	// no text, just close chat bar
-			//	stopChat();
-			//	return TRUE;
-			//}
-
 			if (mask == MASK_CONTROL)
 			{
 				// shout
@@ -239,78 +184,8 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 	return handled;
 }
 
-
-void LLChatBar::layout()
-{
-	if (!mDynamicLayout) return;
-
-	S32 rect_width = mRect.getWidth();
-	S32 count = 9; // number of elements in LLToolBar
-	S32 pad = 4;
-
-	LLRect gesture_rect;
-	S32 gesture_width = 0;
-	if (childGetRect("Gesture", gesture_rect))
-	{
-		gesture_width = gesture_rect.getWidth();
-	}
-	F32 segment_width = (F32)(rect_width - (pad + gesture_width)) / (F32)count;
-
-	S32 btn_width = lltrunc(segment_width-pad);
-
-	S32 x = 0;
-	S32 y = 1;
-	LLRect r;
-
-	x = llround(0 * segment_width);
-	r.setOriginAndSize(x, y, btn_width, BTN_HEIGHT);
-	childSetRect("History", r);
-
-	x = llround(1 * segment_width);
-	// Hack this one up so it looks nice.
-	if (mInputEditor)
-	{
-		r.setOriginAndSize(x, y+2, llfloor(6*segment_width-pad), 18);
-		mInputEditor->reshape(r.getWidth(), r.getHeight(), TRUE);
-		mInputEditor->setRect(r);
-	}
-	
-	x = llround(7 * segment_width);
-	r.setOriginAndSize(x, y, btn_width, BTN_HEIGHT);
-	childSetRect("Say", r);
-
-	x = llround(8 * segment_width);
-	r.setOriginAndSize(x, y, btn_width, BTN_HEIGHT);
-	childSetRect("Shout", r);
-
-	x = rect_width - (pad + gesture_width);
-	r.setOriginAndSize(x, y, gesture_width, BTN_HEIGHT);
-	childSetRect("Gesture", r);
-}
-
-
 void LLChatBar::refresh()
 {
-	//BOOL chat_mode = gSavedSettings.getBOOL("ChatVisible");
-
-	//// Grab focus when no one else has it, and we're in chat mode.
-	//if (!gFocusMgr.getKeyboardFocus()
-	//	&& chat_mode)
-	//{
-	//	childSetFocus("Chat Editor", TRUE);
-	//}
-
-	// Only show this view when user wants to be chatting
-	//setVisible(chat_mode);
-
-	// hide in mouselook, but keep previous visibility state
-	//BOOL mouselook = gAgent.cameraMouselook();
-	// call superclass setVisible so that we don't overwrite the saved setting
-	if (mDynamicLayout)
-	{
-		LLPanel::setVisible(gSavedSettings.getBOOL("ChatVisible"));
-	}
-
 	// HACK: Leave the name of the gesture in place for a few seconds.
 	const F32 SHOW_GESTURE_NAME_TIME = 2.f;
 	if (mGestureLabelTimer.getStarted() && mGestureLabelTimer.getElapsedTimeF32() > SHOW_GESTURE_NAME_TIME)
@@ -584,12 +459,7 @@ void LLChatBar::stopChat()
 
 	// hide chat bar so it doesn't grab focus back
 	gChatBar->setVisible(FALSE);
-}
-
-void LLChatBar::setVisible(BOOL visible)
-{
-	gSavedSettings.setBOOL("ChatVisible", visible);
-	LLPanel::setVisible(visible);
+	gSavedSettings.setBOOL("ChatVisible", FALSE);
 }
 
 // static
@@ -663,30 +533,30 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata )
 }
 
 // static
-void LLChatBar::onInputEditorFocusLost( LLUICtrl* caller, void* userdata)
+void LLChatBar::onInputEditorFocusLost( LLFocusableElement* caller, void* userdata)
 {
 	// stop typing animation
 	gAgent.stopTyping();
 }
 
 // static
-void LLChatBar::onInputEditorGainFocus( LLUICtrl* caller, void* userdata )
+void LLChatBar::onInputEditorGainFocus( LLFocusableElement* caller, void* userdata )
 {
 	LLFloaterChat::setHistoryCursorAndScrollToEnd();
 }
 
 // static
-void LLChatBar::onClickSay( void* userdata )
+void LLChatBar::onClickSay( LLUICtrl* ctrl, void* userdata )
 {
 	LLChatBar* self = (LLChatBar*) userdata;
-	self->sendChat( CHAT_TYPE_NORMAL );
-}
-
-// static
-void LLChatBar::onClickShout( void* userdata )
-{
-	LLChatBar *self = (LLChatBar *)userdata;
-	self->sendChat( CHAT_TYPE_SHOUT );
+	if (ctrl->getValue().asString() == "shout")
+	{
+		self->sendChat( CHAT_TYPE_SHOUT );
+	}
+	else
+	{
+		self->sendChat( CHAT_TYPE_NORMAL );
+	}
 }
 
 void LLChatBar::sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate)
diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h
index 76a80125aeedc65e9d6a37e89eb5361ed8670b6a..f198574dcd1d32c675853d6c58303ba4af261986 100644
--- a/indra/newview/llchatbar.h
+++ b/indra/newview/llchatbar.h
@@ -49,17 +49,12 @@ class LLChatBar
 {
 public:
 	// constructor for inline chat-bars (e.g. hosted in chat history window)
-	LLChatBar(const std::string& name);
-	LLChatBar(const std::string& name, const LLRect& rect);
+	LLChatBar();
 	~LLChatBar();
 	virtual BOOL postBuild();
 
-	virtual void reshape(S32 width, S32 height, BOOL called_from_parent);
 	virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
 
-	// Adjust buttons and input field for width
-	void		layout();
-
 	void		refresh();
 	void		refreshGestures();
 
@@ -86,20 +81,18 @@ class LLChatBar
 	LLWString stripChannelNumber(const LLWString &mesg, S32* channel);
 
 	// callbacks
-	static void	onClickSay( void* userdata );
-	static void	onClickShout( void* userdata );
+	static void	onClickSay( LLUICtrl*, void* userdata );
 
 	static void	onTabClick( void* userdata );
 	static void	onInputEditorKeystroke(LLLineEditor* caller, void* userdata);
-	static void	onInputEditorFocusLost(LLUICtrl* caller,void* userdata);
-	static void	onInputEditorGainFocus(LLUICtrl* caller,void* userdata);
+	static void	onInputEditorFocusLost(LLFocusableElement* caller,void* userdata);
+	static void	onInputEditorGainFocus(LLFocusableElement* caller,void* userdata);
 
 	static void onCommitGesture(LLUICtrl* ctrl, void* data);
 
 	static void startChat(void*);
 	static void stopChat();
 
-	/*virtual*/ void setVisible(BOOL visible);
 protected:
 	void sendChat(EChatType type);
 	void updateChat();
@@ -113,7 +106,6 @@ class LLChatBar
 	S32				mLastSpecialChatChannel;
 
 	BOOL			mIsBuilt;
-	BOOL			mDynamicLayout;
 	LLComboBox*		mGestureCombo;
 
 	LLChatBarGestureObserver* mObserver;
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 693ffe091b1f1bc18668af9f42bf57d5dbf51681..18c3983b9a173793a3b7643b97c5617db10e72dd 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -155,7 +155,6 @@ BOOL LLFloaterAnimPreview::postBuild()
 	mPlayButton->setDisabledImages("","");
 
 	mPlayButton->setScaleImage(TRUE);
-	mPlayButton->setFixedBorder(0, 0);
 
 	mStopButton = LLViewerUICtrlFactory::getButtonByName(this, "stop_btn");
 	if (!mStopButton)
@@ -170,7 +169,6 @@ BOOL LLFloaterAnimPreview::postBuild()
 	mStopButton->setDisabledImages("","");
 
 	mStopButton->setScaleImage(TRUE);
-	mStopButton->setFixedBorder(0, 0);
 
 	r.set(r.mRight + PREVIEW_HPAD, y, getRect().getWidth() - PREVIEW_HPAD, y - BTN_HEIGHT);
 	childSetCommitCallback("playback_slider", onSliderMove, this);
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index a2ea8c2794e6d5132e4f07e842ff9ca279d69b62..8dcd38c0bb24b834dd84bcfdcf796d03b9385a86 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -189,12 +189,15 @@ void LLFloaterAvatarPicker::onList(LLUICtrl* ctrl, void* userdata)
 		return;
 	}
 	
-	std::vector<LLScrollListItem*> items = self->mListNames->getAllSelected();
-	for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
-		 iter != items.end(); ++iter)
+	std::vector<LLScrollListItem*> items =
+		self->mListNames->getAllSelected();
+	for (
+		std::vector<LLScrollListItem*>::iterator iter = items.begin();
+		iter != items.end();
+		++iter)
 	{
 		LLScrollListItem* item = *iter;
-		self->mAvatarNames.push_back(item->getColumn(0)->getText());
+		self->mAvatarNames.push_back(item->getColumn(0)->getValue().asString());
 		self->mAvatarIDs.push_back(item->getUUID());
 		self->childSetEnabled("Select", TRUE);
 	}
@@ -225,8 +228,8 @@ void LLFloaterAvatarPicker::doSelectionChange(const std::deque<LLFolderViewItem*
 		mAvatarNames.clear();
 		childSetEnabled("Select", FALSE);
 	}
+	BOOL first_calling_card = TRUE;
 
-	BOOL	first_calling_card = TRUE;
 	std::deque<LLFolderViewItem*>::const_iterator item_it;
 	for (item_it = items.begin(); item_it != items.end(); ++item_it)
 	{
diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp
index 5fdbf7d4084f45759f0e6d33dadd0a28e45f836c..82fe16172b48402b59d8b9b7285ce8706911aded 100644
--- a/indra/newview/llfloaterchat.cpp
+++ b/indra/newview/llfloaterchat.cpp
@@ -164,10 +164,16 @@ void LLFloaterChat::onVisibilityChange(BOOL new_visibility)
 {
 	// Hide the chat overlay when our history is visible.
 	gConsole->setVisible( !new_visibility );
+
+	// stop chat history tab from flashing when it appears
+	if (new_visibility)
+	{
+		LLFloaterChatterBox::getInstance()->setFloaterFlashing(this, FALSE);
+	}
+
 	LLFloater::onVisibilityChange(new_visibility);
 }
 
-
 void add_timestamped_line(LLViewerTextEditor* edit, const LLString& line, const LLColor4& color)
 {
 	bool prepend_newline = true;
@@ -238,6 +244,12 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file)
 	{
 		chat_floater->mPanel->setSpeaker(chat.mFromID, chat.mFromName, LLSpeaker::STATUS_NOT_IN_CHANNEL, LLSpeaker::SPEAKER_OBJECT);
 	}
+
+	// start tab flashing on incoming text from other users (ignoring system text, etc)
+	if (!chat_floater->isInVisibleChain() && chat.mSourceType == CHAT_SOURCE_AGENT)
+	{
+		LLFloaterChatterBox::getInstance()->setFloaterFlashing(chat_floater, TRUE);
+	}
 }
 
 // static
@@ -246,8 +258,14 @@ void LLFloaterChat::setHistoryCursorAndScrollToEnd()
 	LLViewerTextEditor*	history_editor = (LLViewerTextEditor*)LLFloaterChat::getInstance(LLSD())->getChildByName("Chat History Editor", TRUE);
 	LLViewerTextEditor*	history_editor_with_mute = (LLViewerTextEditor*)LLFloaterChat::getInstance(LLSD())->getChildByName("Chat History Editor with mute", TRUE);
 	
-	history_editor->setCursorAndScrollToEnd();
-	history_editor_with_mute->setCursorAndScrollToEnd();
+	if (history_editor) 
+	{
+		history_editor->setCursorAndScrollToEnd();
+	}
+	if (history_editor_with_mute)
+	{
+		 history_editor_with_mute->setCursorAndScrollToEnd();
+	}
 }
 
 
@@ -269,7 +287,7 @@ void LLFloaterChat::onClickMute(void *data)
 	
 	if (gFloaterMute)
 	{
-		gFloaterMute->show();
+		LLFloaterMute::showInstance();
 	}
 }
 
@@ -433,7 +451,7 @@ void* LLFloaterChat::createSpeakersPanel(void* data)
 //static
 void* LLFloaterChat::createChatPanel(void* data)
 {
-	LLChatBar* chatp = new LLChatBar("floating_chat_bar");
+	LLChatBar* chatp = new LLChatBar();
 	return chatp;
 }
 
@@ -441,7 +459,7 @@ void* LLFloaterChat::createChatPanel(void* data)
 void LLFloaterChat::hideInstance(const LLSD& id)
 {
 	LLFloaterChat* floaterp = LLFloaterChat::getInstance(LLSD());
-	// don't do anything when hosted in the chatterbox
+
 	if(floaterp->getHost())
 	{
 		LLFloaterChatterBox::hideInstance(LLSD());
diff --git a/indra/newview/llfloaterchat.h b/indra/newview/llfloaterchat.h
index 808393b267aca73a9a5bb39fea6254391559f4d9..58fa607b3863c319fc1a6f6758709506af360de5 100644
--- a/indra/newview/llfloaterchat.h
+++ b/indra/newview/llfloaterchat.h
@@ -82,6 +82,7 @@ class LLFloaterChat
 
 protected:
 	LLPanelActiveSpeakers* mPanel;
+	BOOL mScrolledToEnd;
 };
 
 #endif
diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp
index bdd30906d2eb80fee6517632141f01ee12626938..85bc8182a5a635672754f84cda3bc1efd8b8dc51 100644
--- a/indra/newview/llfloaterchatterbox.cpp
+++ b/indra/newview/llfloaterchatterbox.cpp
@@ -86,9 +86,15 @@ LLFloaterMyFriends* LLFloaterMyFriends::showInstance(const LLSD& id)
 //static 
 void LLFloaterMyFriends::hideInstance(const LLSD& id)
 {
-	if(instanceVisible(id))
+	LLFloaterMyFriends* floaterp = LLFloaterMyFriends::getInstance();
+
+	if(floaterp->getHost())
 	{
-		LLFloaterChatterBox::hideInstance(LLSD());
+		LLFloaterChatterBox::hideInstance();
+	}
+	else
+	{
+		LLUISingleton<LLFloaterMyFriends>::hideInstance(id);
 	}
 }
 
@@ -124,10 +130,23 @@ LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) :
 	mAutoResize = FALSE;
 
 	gUICtrlFactory->buildFloater(this, "floater_chatterbox.xml", NULL, FALSE);
-	addFloater(LLFloaterMyFriends::getInstance(0), TRUE);
+	if (gSavedSettings.getBOOL("ContactsTornOff"))
+	{
+		LLFloaterMyFriends* floater_contacts = LLFloaterMyFriends::getInstance(0);
+		// add then remove to set up relationship for re-attach
+		addFloater(floater_contacts, FALSE);
+		removeFloater(floater_contacts);
+		// reparent to floater view
+		gFloaterView->addChild(floater_contacts);
+	}
+	else
+	{
+		addFloater(LLFloaterMyFriends::getInstance(0), TRUE);
+	}
+
 	if (gSavedSettings.getBOOL("ChatHistoryTornOff"))
 	{
-		LLFloaterChat* floater_chat = LLFloaterChat::getInstance(LLSD());
+		LLFloaterChat* floater_chat = LLFloaterChat::getInstance();
 		// add then remove to set up relationship for re-attach
 		addFloater(floater_chat, FALSE);
 		removeFloater(floater_chat);
@@ -217,7 +236,7 @@ void LLFloaterChatterBox::draw()
 
 	mActiveVoiceFloater = current_active_floater;
 
-	LLFloater::draw();
+	LLMultiFloater::draw();
 }
 
 void LLFloaterChatterBox::onOpen()
@@ -236,10 +255,17 @@ void LLFloaterChatterBox::removeFloater(LLFloater* floaterp)
 	if (floaterp->getName() == "chat floater")
 	{
 		// only my friends floater now locked
-		mTabContainer->lockTabs(1);
+		mTabContainer->lockTabs(mTabContainer->getNumLockedTabs() - 1);
 		gSavedSettings.setBOOL("ChatHistoryTornOff", TRUE);
 		floaterp->setCanClose(TRUE);
 	}
+	else if (floaterp->getName() == "floater_my_friends")
+	{
+		// only chat floater now locked
+		mTabContainer->lockTabs(mTabContainer->getNumLockedTabs() - 1);
+		gSavedSettings.setBOOL("ContactsTornOff", TRUE);
+		floaterp->setCanClose(TRUE);
+	}
 	LLMultiFloater::removeFloater(floaterp);
 }
 
@@ -247,19 +273,43 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp,
 									BOOL select_added_floater, 
 									LLTabContainerCommon::eInsertionPoint insertion_point)
 {
+	S32 num_locked_tabs = mTabContainer->getNumLockedTabs();
+
+	// already here
+	if (floaterp->getHost() == this) return;
+
 	// make sure my friends and chat history both locked when re-attaching chat history
 	if (floaterp->getName() == "chat floater")
 	{
-		// select my friends tab
-		mTabContainer->selectFirstTab();
-		// add chat history to the right of the my friends tab
-		//*TODO: respect select_added_floater so that we don't leave first tab selected
-		LLMultiFloater::addFloater(floaterp, select_added_floater, LLTabContainer::RIGHT_OF_CURRENT);
+		mTabContainer->unlockTabs();
+		// add chat history as second tab if contact window is present, first tab otherwise
+		if (getChildByName("floater_my_friends", TRUE))
+		{
+			// assuming contacts window is first tab, select it
+			mTabContainer->selectFirstTab();
+			// and add ourselves after
+			LLMultiFloater::addFloater(floaterp, select_added_floater, LLTabContainer::RIGHT_OF_CURRENT);
+		}
+		else
+		{
+			LLMultiFloater::addFloater(floaterp, select_added_floater, LLTabContainer::START);
+		}
+		
 		// make sure first two tabs are now locked
-		mTabContainer->lockTabs(2);
+		mTabContainer->lockTabs(num_locked_tabs + 1);
 		gSavedSettings.setBOOL("ChatHistoryTornOff", FALSE);
 		floaterp->setCanClose(FALSE);
 	}
+	else if (floaterp->getName() == "floater_my_friends")
+	{
+		mTabContainer->unlockTabs();
+		// add contacts window as first tab
+		LLMultiFloater::addFloater(floaterp, select_added_floater, LLTabContainer::START);
+		// make sure first two tabs are now locked
+		mTabContainer->lockTabs(num_locked_tabs + 1);
+		gSavedSettings.setBOOL("ContactsTornOff", FALSE);
+		floaterp->setCanClose(FALSE);
+	}
 	else
 	{
 		LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point);
@@ -276,24 +326,27 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp,
 //static 
 LLFloaterChatterBox* LLFloaterChatterBox::showInstance(const LLSD& seed)
 {
-	LLFloaterChatterBox* floater = LLUISingleton<LLFloaterChatterBox>::showInstance(seed);
+	LLFloaterChatterBox* chatterbox_floater = LLUISingleton<LLFloaterChatterBox>::showInstance(seed);
 
 	// if TRUE, show tab for active voice channel, otherwise, just show last tab
-	if (seed.asBoolean())
+	LLFloater* floater_to_show = NULL;
+	LLUUID session_id = seed.asUUID();
+	if (session_id.notNull())
 	{
-		LLFloater* floater_to_show = getCurrentVoiceFloater();
-		if (floater_to_show)
-		{
-			floater_to_show->open();
-		}
-		else
-		{
-			// just open chatterbox if there is no active voice window
-			LLUISingleton<LLFloaterChatterBox>::getInstance(seed)->open();
-		}
+		floater_to_show = gIMMgr->findFloaterBySession(session_id);
+	}
+
+	if (floater_to_show)
+	{
+		floater_to_show->open();
+	}
+	else
+	{
+		// just open chatterbox to the last selected tab
+		chatterbox_floater->open();
 	}
 	
-	return floater;
+	return chatterbox_floater;
 }
 
 //static
diff --git a/indra/newview/llfloaterchatterbox.h b/indra/newview/llfloaterchatterbox.h
index 34410935f2cea60e27bc709dc3ffca537272f6df..bf06ee9d38f65865a3c8dc771a401355d9601ffa 100644
--- a/indra/newview/llfloaterchatterbox.h
+++ b/indra/newview/llfloaterchatterbox.h
@@ -50,7 +50,7 @@ class LLFloaterMyFriends : public LLFloater, public LLUISingleton<LLFloaterMyFri
 	void onClose(bool app_quitting);
 
 	// override LLUISingleton behavior
-	static LLFloaterMyFriends* showInstance(const LLSD& id);
+	static LLFloaterMyFriends* showInstance(const LLSD& id = LLSD());
 	static void hideInstance(const LLSD& id);
 	static BOOL instanceVisible(const LLSD& id);
 
@@ -77,7 +77,7 @@ class LLFloaterChatterBox : public LLMultiFloater, public LLUISingleton<LLFloate
 								BOOL select_added_floater, 
 								LLTabContainerCommon::eInsertionPoint insertion_point = LLTabContainerCommon::END);
 
-	static LLFloaterChatterBox* showInstance(const LLSD& seed);
+	static LLFloaterChatterBox* showInstance(const LLSD& seed = LLSD());
 	static BOOL instanceVisible(const LLSD& seed);
 
 	static LLFloater* getCurrentVoiceFloater();
diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp
index 6f4945e54b09d5b7c8e23a3cf8af97c0182e1696..9d52107a206d5750559f91f04966ea462f8c37a7 100644
--- a/indra/newview/llfloaterfriends.cpp
+++ b/indra/newview/llfloaterfriends.cpp
@@ -104,7 +104,6 @@ LLPanelFriends::LLPanelFriends() :
 	LLPanel(),
 	LLEventTimer(1000000),
 	mObserver(NULL),
-	mMenuState(0),
 	mShowMaxSelectWarning(TRUE),
 	mAllowRightsChange(TRUE),
 	mNumRightsChanged(0)
@@ -182,16 +181,13 @@ BOOL LLPanelFriends::postBuild()
 {
 	mFriendsList = LLUICtrlFactory::getScrollListByName(this, "friend_list");
 	mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT);
-	mFriendsList->setMaxiumumSelectCallback(onMaximumSelect);
+	mFriendsList->setMaximumSelectCallback(onMaximumSelect);
 	mFriendsList->setCommitOnSelectionChange(TRUE);
 	childSetCommitCallback("friend_list", onSelectName, this);
 	childSetDoubleClickCallback("friend_list", onClickIM);
 
 	refreshNames();
 
-	childSetCommitCallback("online_status_cb", onClickOnlineStatus, this);
-	childSetCommitCallback("map_status_cb", onClickMapStatus, this);
-	childSetCommitCallback("modify_status_cb", onClickModifyStatus, this);
 	childSetAction("im_btn", onClickIM, this);
 	childSetAction("profile_btn", onClickProfile, this);
 	childSetAction("offer_teleport_btn", onClickOfferTeleport, this);
@@ -204,6 +200,10 @@ BOOL LLPanelFriends::postBuild()
 	updateFriends(LLFriendObserver::ADD);
 	refreshUI();
 
+	// primary sort = online status, secondary sort = name
+	mFriendsList->sortByColumn("friend_name", TRUE);
+	mFriendsList->sortByColumn("icon_online_status", TRUE);
+
 	return TRUE;
 }
 
@@ -222,64 +222,63 @@ void LLPanelFriends::addFriend(const std::string& name, const LLUUID& agent_id)
 	element["columns"][LIST_FRIEND_NAME]["font"] = "SANSSERIF";
 	element["columns"][LIST_FRIEND_NAME]["font-style"] = "NORMAL";	
 	element["columns"][LIST_ONLINE_STATUS]["column"] = "icon_online_status";
-	element["columns"][LIST_ONLINE_STATUS]["type"] = "text";
+	element["columns"][LIST_ONLINE_STATUS]["type"] = "icon";
 	if (online)
 	{
 		element["columns"][LIST_FRIEND_NAME]["font-style"] = "BOLD";	
-		element["columns"][LIST_ONLINE_STATUS]["type"] = "icon";
 		element["columns"][LIST_ONLINE_STATUS]["value"] = gViewerArt.getString("icon_avatar_online.tga");		
 	}
 
-
 	element["columns"][LIST_VISIBLE_ONLINE]["column"] = "icon_visible_online";
-	element["columns"][LIST_VISIBLE_ONLINE]["type"] = "text";
-	if(relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS))
-	{
-		element["columns"][LIST_VISIBLE_ONLINE]["type"] = "icon";
-		element["columns"][LIST_VISIBLE_ONLINE]["value"] = gViewerArt.getString("ff_visible_online.tga");
-	}
+	element["columns"][LIST_VISIBLE_ONLINE]["type"] = "checkbox";
+	element["columns"][LIST_VISIBLE_ONLINE]["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS);
+
 	element["columns"][LIST_VISIBLE_MAP]["column"] = "icon_visible_map";
-	element["columns"][LIST_VISIBLE_MAP]["type"] = "text";
-	if(relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))
-	{
-		element["columns"][LIST_VISIBLE_MAP]["type"] = "icon";
-		element["columns"][LIST_VISIBLE_MAP]["value"] = gViewerArt.getString("ff_visible_map.tga");
-	}
+	element["columns"][LIST_VISIBLE_MAP]["type"] = "checkbox";
+	element["columns"][LIST_VISIBLE_MAP]["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION);
+
 	element["columns"][LIST_EDIT_MINE]["column"] = "icon_edit_mine";
-	element["columns"][LIST_EDIT_MINE]["type"] = "text";
-	if(relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS))
-	{
-		element["columns"][LIST_EDIT_MINE]["type"] = "icon";
-		element["columns"][LIST_EDIT_MINE]["value"] = gViewerArt.getString("ff_edit_mine.tga");
-	}
+	element["columns"][LIST_EDIT_MINE]["type"] = "checkbox";
+	element["columns"][LIST_EDIT_MINE]["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
+
 	element["columns"][LIST_EDIT_THEIRS]["column"] = "icon_edit_theirs";
-	element["columns"][LIST_EDIT_THEIRS]["type"] = "text";
-	if(relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS))
-	{
-		element["columns"][LIST_EDIT_THEIRS]["type"] = "icon";
-		element["columns"][LIST_EDIT_THEIRS]["value"] = gViewerArt.getString("ff_edit_theirs.tga");
-	}
+	element["columns"][LIST_EDIT_THEIRS]["type"] = "checkbox";
+	element["columns"][LIST_EDIT_THEIRS]["enabled"] = "";
+	element["columns"][LIST_EDIT_THEIRS]["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS);
+
+	element["columns"][LIST_FRIEND_UPDATE_GEN]["column"] = "friend_last_update_generation";
+	element["columns"][LIST_FRIEND_UPDATE_GEN]["value"] = relationInfo->getChangeSerialNum();
+
 	mFriendsList->addElement(element, ADD_BOTTOM);
 }
 
+// propagate actual relationship to UI
+void LLPanelFriends::updateFriendItem(LLScrollListItem* itemp, const LLRelationship* info)
+{
+	if (!itemp) return;
+	if (!info) return;
+
+	itemp->getColumn(LIST_ONLINE_STATUS)->setValue(info->isOnline() ? gViewerArt.getString("icon_avatar_online.tga") : LLString());
+	// render name of online friends in bold text
+	((LLScrollListText*)itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle(info->isOnline() ? LLFontGL::BOLD : LLFontGL::NORMAL);	
+	itemp->getColumn(LIST_VISIBLE_ONLINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS));
+	itemp->getColumn(LIST_VISIBLE_MAP)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION));
+	itemp->getColumn(LIST_EDIT_MINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS));
+	itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(info->getChangeSerialNum());
+
+	// enable this item, in case it was disabled after user input
+	itemp->setEnabled(TRUE);
+
+	// changed item in place, need to request sort
+	mFriendsList->sortItems();
+}
+
 void LLPanelFriends::refreshRightsChangeList()
 {
 	LLDynamicArray<LLUUID> friends = getSelectedIDs();
 	S32 num_selected = friends.size();
 
-	LLSD row;
 	bool can_offer_teleport = num_selected >= 1;
-
-	// aggregate permissions over all selected friends
-	bool friends_see_online = true;
-	bool friends_see_on_map = true;
-	bool friends_modify_objects = true;
-
-	// do at least some of the friends selected have these rights?
-	bool some_friends_see_online = false;
-	bool some_friends_see_on_map = false;
-	bool some_friends_modify_objects = false;
-
 	bool selected_friends_online = true;
 
 	LLTextBox* processing_label = LLUICtrlFactory::getTextBoxByName(this, "process_rights_label");
@@ -294,12 +293,9 @@ void LLPanelFriends::refreshRightsChangeList()
 			num_selected = 0;
 		}
 	}
-	else
+	else if(processing_label)
 	{
-		if(processing_label)
-		{
-			processing_label->setVisible(false);
-		}
+		processing_label->setVisible(false);
 	}
 
 	const LLRelationship* friend_status = NULL;
@@ -308,20 +304,6 @@ void LLPanelFriends::refreshRightsChangeList()
 		friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr);
 		if (friend_status)
 		{
-			bool can_see_online = friend_status->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS);
-			bool can_see_on_map = friend_status->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION);
-			bool can_modify_objects = friend_status->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
-
-			// aggregate rights of this friend into total selection
-			friends_see_online &= can_see_online;
-			friends_see_on_map &= can_see_on_map;
-			friends_modify_objects &= can_modify_objects;
-
-			// can at least one of your selected friends do any of these?
-			some_friends_see_online |= can_see_online;
-			some_friends_see_on_map |= can_see_on_map;
-			some_friends_modify_objects |= can_modify_objects;
-
 			if(!friend_status->isOnline())
 			{
 				can_offer_teleport = false;
@@ -331,44 +313,13 @@ void LLPanelFriends::refreshRightsChangeList()
 		else // missing buddy info, don't allow any operations
 		{
 			can_offer_teleport = false;
-
-			friends_see_online = false;
-			friends_see_on_map = false;
-			friends_modify_objects = false;
-
-			some_friends_see_online = false;
-			some_friends_see_on_map = false;
-			some_friends_modify_objects = false;
 		}
 	}
 	
-
-	// seeing a friend on the map requires seeing online status as a prerequisite
-	friends_see_on_map &= friends_see_online;
-
-	mMenuState = 0;
-
-	// make checkboxes visible after we have finished processing rights
-	childSetVisible("online_status_cb", mAllowRightsChange);
-	childSetVisible("map_status_cb", mAllowRightsChange);
-	childSetVisible("modify_status_cb", mAllowRightsChange);
-
 	if (num_selected == 0)  // nothing selected
 	{
 		childSetEnabled("im_btn", FALSE);
 		childSetEnabled("offer_teleport_btn", FALSE);
-
-		childSetEnabled("online_status_cb", FALSE);
-		childSetValue("online_status_cb", FALSE);
-		childSetTentative("online_status_cb", FALSE);
-
-		childSetEnabled("map_status_cb", FALSE);
-		childSetValue("map_status_cb", FALSE);
-		childSetTentative("map_status_cb", FALSE);
-
-		childSetEnabled("modify_status_cb", FALSE);
-		childSetValue("modify_status_cb", FALSE);
-		childSetTentative("modify_status_cb", FALSE);
 	}
 	else // we have at least one friend selected...
 	{
@@ -376,61 +327,76 @@ void LLPanelFriends::refreshRightsChangeList()
 		// to be consistent with context menus in inventory and because otherwise
 		// offline friends would be silently dropped from the session
 		childSetEnabled("im_btn", selected_friends_online || num_selected == 1);
-
 		childSetEnabled("offer_teleport_btn", can_offer_teleport);
-
-		childSetEnabled("online_status_cb", TRUE);
-		childSetValue("online_status_cb", some_friends_see_online);
-		childSetTentative("online_status_cb", some_friends_see_online != friends_see_online);
-		if (friends_see_online)
-		{
-			mMenuState |= LLRelationship::GRANT_ONLINE_STATUS;
-		}
-
-		childSetEnabled("map_status_cb", TRUE);
-		childSetValue("map_status_cb", some_friends_see_on_map);
-		childSetTentative("map_status_cb", some_friends_see_on_map != friends_see_on_map);
-		if(friends_see_on_map) 
-		{
-			mMenuState |= LLRelationship::GRANT_MAP_LOCATION;
-		}
-
-		// for now, don't allow modify rights change for multiple select
-		childSetEnabled("modify_status_cb", num_selected == 1);
-		childSetValue("modify_status_cb", some_friends_modify_objects);
-		childSetTentative("modify_status_cb", some_friends_modify_objects != friends_modify_objects);
-		if(friends_modify_objects) 
-		{
-			mMenuState |= LLRelationship::GRANT_MODIFY_OBJECTS;
-		}
 	}
 }
 
+struct SortFriendsByID
+{
+	bool SortFriendsByID::operator() (const LLScrollListItem* const a, const LLScrollListItem* const b) const
+	{
+		return a->getValue().asUUID() < b->getValue().asUUID();
+	}
+};
+
 void LLPanelFriends::refreshNames()
 {
 	LLDynamicArray<LLUUID> selected_ids = getSelectedIDs();	
 	S32 pos = mFriendsList->getScrollPos();	
-	mFriendsList->operateOnAll(LLCtrlListInterface::OP_DELETE);
 	
-	LLCollectAllBuddies collect;
-	LLAvatarTracker::instance().applyFunctor(collect);
-	LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin();
-	LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end();
+	// get all buddies we know about
+	LLAvatarTracker::buddy_map_t all_buddies;
+	LLAvatarTracker::instance().copyBuddyList(all_buddies);
 	
-	for ( ; it != end; ++it)
-	{
-		const std::string& name = it->first;
-		const LLUUID& agent_id = it->second;
-		addFriend(name, agent_id);
-	}
-	it = collect.mOffline.begin();
-	end = collect.mOffline.end();
-	for ( ; it != end; ++it)
+	// get all friends in list and sort by UUID
+	std::vector<LLScrollListItem*> items = mFriendsList->getAllData();
+	std::sort(items.begin(), items.end(), SortFriendsByID());
+
+	std::vector<LLScrollListItem*>::iterator item_it = items.begin();
+	std::vector<LLScrollListItem*>::iterator item_end = items.end();
+	
+	LLAvatarTracker::buddy_map_t::iterator buddy_it;
+	for (buddy_it = all_buddies.begin() ; buddy_it != all_buddies.end(); ++buddy_it)
 	{
-		const std::string& name = it->first;
-		const LLUUID& agent_id = it->second;
-		addFriend(name, agent_id);
+		// erase any items that reflect residents who are no longer buddies
+		while(item_it != item_end && buddy_it->first > (*item_it)->getValue().asUUID())
+		{
+			mFriendsList->deleteItems((*item_it)->getValue());
+			++item_it;
+		}
+
+		// update existing friends with new info
+		if (item_it != item_end && buddy_it->first == (*item_it)->getValue().asUUID())
+		{
+			const LLRelationship* info = buddy_it->second;
+			if (!info) 
+			{	
+				++item_it;
+				continue;
+			}
+			
+			S32 last_change_generation = (*item_it)->getColumn(LIST_FRIEND_UPDATE_GEN)->getValue().asInteger();
+			if (last_change_generation < info->getChangeSerialNum())
+			{
+				// update existing item in UI
+				updateFriendItem(mFriendsList->getItem(buddy_it->first), info);
+			}
+			++item_it;
+		}
+		// add new friend to list
+		else 
+		{
+			const LLUUID& buddy_id = buddy_it->first;
+			char first_name[DB_FIRST_NAME_BUF_SIZE];	/*Flawfinder: ignore*/	
+			char last_name[DB_LAST_NAME_BUF_SIZE];		/*Flawfinder: ignore*/
+
+			gCacheName->getName(buddy_id, first_name, last_name);
+			std::ostringstream fullname;
+			fullname << first_name << " " << last_name;
+			addFriend(fullname.str(), buddy_id);
+		}
 	}
+
 	mFriendsList->selectMultiple(selected_ids);
 	mFriendsList->setScrollPos(pos);
 }
@@ -451,7 +417,7 @@ void LLPanelFriends::refreshUI()
 		}
 		else
 		{			
-			childSetText("friend_name_label", mFriendsList->getFirstSelected()->getColumn(LIST_FRIEND_NAME)->getText() + "...");
+			childSetText("friend_name_label", mFriendsList->getFirstSelected()->getColumn(LIST_FRIEND_NAME)->getValue().asString() + "...");
 		}
 	}
 	else
@@ -493,6 +459,8 @@ void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data)
 	if(panelp)
 	{
 		panelp->refreshUI();
+		// check to see if rights have changed
+		panelp->applyRightsToFriends();
 	}
 }
 
@@ -687,35 +655,22 @@ void LLPanelFriends::onClickPay(void* user_data)
 	}
 }
 
-void LLPanelFriends::onClickOnlineStatus(LLUICtrl* ctrl, void* user_data)
-{
-	LLPanelFriends* panelp = (LLPanelFriends*)user_data;
-
-	bool checked = ctrl->getValue();
-	panelp->updateMenuState(LLRelationship::GRANT_ONLINE_STATUS, checked);
-	panelp->applyRightsToFriends(LLRelationship::GRANT_ONLINE_STATUS, checked);
-}
-
-void LLPanelFriends::onClickMapStatus(LLUICtrl* ctrl, void* user_data)
-{
-	LLPanelFriends* panelp = (LLPanelFriends*)user_data;
-	bool checked = ctrl->getValue();
-	panelp->updateMenuState(LLRelationship::GRANT_MAP_LOCATION, checked);
-	panelp->applyRightsToFriends(LLRelationship::GRANT_MAP_LOCATION, checked);
-}
-
-void LLPanelFriends::onClickModifyStatus(LLUICtrl* ctrl, void* user_data)
+void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command)
 {
-	LLPanelFriends* panelp = (LLPanelFriends*)user_data;
-
-	bool checked = ctrl->getValue();
-	LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
+	if (ids.empty()) return;
+	
 	LLStringBase<char>::format_map_t args;
 	if(ids.size() > 0)
 	{
+		// copy map of ids onto heap
+		rights_map_t* rights = new rights_map_t(ids); 
+		// package with panel pointer
+		std::pair<LLPanelFriends*, rights_map_t*>* user_data = new std::pair<LLPanelFriends*, rights_map_t*>(this, rights);
+
+		// for single friend, show their name
 		if(ids.size() == 1)
 		{
-			LLUUID agent_id = ids[0];
+			LLUUID agent_id = ids.begin()->first;
 			char first[DB_FIRST_NAME_BUF_SIZE];		/*Flawfinder: ignore*/
 			char last[DB_LAST_NAME_BUF_SIZE];		/*Flawfinder: ignore*/
 			if(gCacheName->getName(agent_id, first, last))
@@ -723,56 +678,174 @@ void LLPanelFriends::onClickModifyStatus(LLUICtrl* ctrl, void* user_data)
 				args["[FIRST_NAME]"] = first;
 				args["[LAST_NAME]"] = last;	
 			}
-			if(checked) gViewerWindow->alertXml("GrantModifyRights", args, handleModifyRights, user_data);
-			else gViewerWindow->alertXml("RevokeModifyRights", args, handleModifyRights, user_data);
+			if (command == GRANT)
+			{
+				gViewerWindow->alertXml("GrantModifyRights", args, modifyRightsConfirmation, user_data);
+			}
+			else
+			{
+				gViewerWindow->alertXml("RevokeModifyRights", args, modifyRightsConfirmation, user_data);
+			}
+		}
+		else
+		{
+			if (command == GRANT)
+			{
+				gViewerWindow->alertXml("GrantModifyRightsMultiple", args, modifyRightsConfirmation, user_data);
+			}
+			else
+			{
+				gViewerWindow->alertXml("RevokeModifyRightsMultiple", args, modifyRightsConfirmation, user_data);
+			}
 		}
-		else return;
 	}
 }
 
-void LLPanelFriends::handleModifyRights(S32 option, void* user_data)
+// static
+void LLPanelFriends::modifyRightsConfirmation(S32 option, void* user_data)
 {
-	LLPanelFriends* panelp = (LLPanelFriends*)user_data;
+	std::pair<LLPanelFriends*, rights_map_t*>* data = (std::pair<LLPanelFriends*, rights_map_t*>*)user_data;
+	LLPanelFriends* panelp = data->first;
 
 	if(panelp)
 	{
-		if(!option)
+		if(0 == option)
 		{
-			panelp->updateMenuState(LLRelationship::GRANT_MODIFY_OBJECTS, !((panelp->getMenuState() & LLRelationship::GRANT_MODIFY_OBJECTS) != 0));
-			panelp->applyRightsToFriends(LLRelationship::GRANT_MODIFY_OBJECTS, ((panelp->getMenuState() & LLRelationship::GRANT_MODIFY_OBJECTS) != 0));
+			panelp->sendRightsGrant(*(data->second));
+		}
+		else
+		{
+			// need to resync view with model, since user cancelled operation
+			rights_map_t* rights = data->second;
+			rights_map_t::iterator rights_it;
+			for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it)
+			{
+				LLScrollListItem* itemp = panelp->mFriendsList->getItem(rights_it->first);
+				const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first);
+				panelp->updateFriendItem(itemp, info);
+			}
 		}
 		panelp->refreshUI();
 	}
+
+	delete data->second;
+	delete data;
 }
 
-void LLPanelFriends::updateMenuState(S32 flag, BOOL value)
+void LLPanelFriends::applyRightsToFriends()
 {
-	if(value) mMenuState |= flag;
-	else mMenuState &= ~flag;
+	BOOL rights_changed = FALSE;
+
+	// store modify rights separately for confirmation
+	rights_map_t rights_updates;
+
+	BOOL need_confirmation = FALSE;
+	EGrantRevoke confirmation_type = GRANT;
+
+	// this assumes that changes only happened to selected items
+	std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
+	for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
+	{
+		LLUUID id = (*itr)->getValue();
+		const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(id);
+		if (buddy_relationship == NULL) continue;
+
+		bool show_online_staus = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean();
+		bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean();
+		bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean();
+
+		S32 rights = buddy_relationship->getRightsGrantedTo();
+		if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus)
+		{
+			rights_changed = TRUE;
+			if(show_online_staus) 
+			{
+				rights |= LLRelationship::GRANT_ONLINE_STATUS;
+			}
+			else 
+			{
+				// ONLINE_STATUS necessary for MAP_LOCATION
+				rights &= ~LLRelationship::GRANT_ONLINE_STATUS;
+				rights &= ~LLRelationship::GRANT_MAP_LOCATION;
+				// propagate rights constraint to UI
+				(*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(FALSE);
+			}
+		}
+		if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location)
+		{
+			rights_changed = TRUE;
+			if(show_map_location) 
+			{
+				// ONLINE_STATUS necessary for MAP_LOCATION
+				rights |= LLRelationship::GRANT_MAP_LOCATION;
+				rights |= LLRelationship::GRANT_ONLINE_STATUS;
+				(*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(TRUE);
+			}
+			else 
+			{
+				rights &= ~LLRelationship::GRANT_MAP_LOCATION;
+			}
+		}
+		
+		// now check for change in modify object rights, which requires confirmation
+		if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects)
+		{
+			rights_changed = TRUE;
+			need_confirmation = TRUE;
+
+			if(allow_modify_objects)
+			{
+				rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
+				confirmation_type = GRANT;
+			}
+			else
+			{
+				rights &= ~LLRelationship::GRANT_MODIFY_OBJECTS;
+				confirmation_type = REVOKE;
+			}
+		}
+
+		if (rights_changed)
+		{
+			rights_updates.insert(std::make_pair(id, rights));
+			// disable these ui elements until response from server
+			// to avoid race conditions
+			(*itr)->setEnabled(FALSE);
+		}
+	}
+
+	// separately confirm grant and revoke of modify rights
+	if (need_confirmation)
+	{
+		confirmModifyRights(rights_updates, confirmation_type);
+	}
+	else
+	{
+		sendRightsGrant(rights_updates);
+	}
 }
 
-void LLPanelFriends::applyRightsToFriends(S32 flag, BOOL value)
+void LLPanelFriends::sendRightsGrant(rights_map_t& ids)
 {
+	if (ids.empty()) return;
+
 	LLMessageSystem* msg = gMessageSystem;
+
+	// setup message header
 	msg->newMessageFast(_PREHASH_GrantUserRights);
 	msg->nextBlockFast(_PREHASH_AgentData);
 	msg->addUUID(_PREHASH_AgentID, gAgent.getID());
 	msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
 
-	LLDynamicArray<LLUUID> ids = getSelectedIDs();
-	S32 rights;
-	for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
+	rights_map_t::iterator id_it;
+	rights_map_t::iterator end_it = ids.end();
+	for(id_it = ids.begin(); id_it != end_it; ++id_it)
 	{
-		rights = LLAvatarTracker::instance().getBuddyInfo(*itr)->getRightsGrantedTo();
-		if(LLAvatarTracker::instance().getBuddyInfo(*itr)->isRightGrantedTo(flag) != (bool)value)
-		{
-			if(value) rights |= flag;
-			else rights &= ~flag;
-			msg->nextBlockFast(_PREHASH_Rights);
-			msg->addUUID(_PREHASH_AgentRelated, *itr);
-			msg->addS32(_PREHASH_RelatedRights, rights);
-		}
+		msg->nextBlockFast(_PREHASH_Rights);
+		msg->addUUID(_PREHASH_AgentRelated, id_it->first);
+		msg->addS32(_PREHASH_RelatedRights, id_it->second);
 	}
+
 	mNumRightsChanged = ids.size();
 	gAgent.sendReliableMessage();
 }
diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h
index 3d0b7a9bba36b7fbc1cd1786456a9b58733f2a50..46e4eaaf7925a9a1ba489c32cfdd9b951e0de272 100644
--- a/indra/newview/llfloaterfriends.h
+++ b/indra/newview/llfloaterfriends.h
@@ -40,6 +40,7 @@
 #include "lltimer.h"
 
 class LLFriendObserver;
+class LLRelationship;
 
 
 /** 
@@ -88,19 +89,27 @@ class LLPanelFriends : public LLPanel, public LLEventTimer
 		LIST_VISIBLE_ONLINE,
 		LIST_VISIBLE_MAP,
 		LIST_EDIT_MINE,
-		LIST_EDIT_THEIRS
+		LIST_EDIT_THEIRS,
+		LIST_FRIEND_UPDATE_GEN
 	};
 
 	// protected members
-
+	typedef std::map<LLUUID, S32> rights_map_t;
 	void reloadNames();
 	void refreshNames();
 	void refreshUI();
 	void refreshRightsChangeList();
-	void applyRightsToFriends(S32 flag, BOOL value);
-	void updateMenuState(S32 flag, BOOL value);
-	S32 getMenuState() { return mMenuState; }
+	void applyRightsToFriends();
 	void addFriend(const std::string& name, const LLUUID& agent_id);	
+	void updateFriendItem(LLScrollListItem* itemp, const LLRelationship* relationship);
+
+	typedef enum 
+	{
+		GRANT,
+		REVOKE
+	} EGrantRevoke;
+	void confirmModifyRights(rights_map_t& ids, EGrantRevoke command);
+	void sendRightsGrant(rights_map_t& ids);
 
 	// return LLUUID::null if nothing is selected
 	LLDynamicArray<LLUUID> getSelectedIDs();
@@ -119,12 +128,10 @@ class LLPanelFriends : public LLPanel, public LLEventTimer
 	static void onClickOfferTeleport(void* user_data);
 	static void onClickPay(void* user_data);
 
-	static void onClickOnlineStatus(LLUICtrl* ctrl, void* user_data);
-	static void onClickMapStatus(LLUICtrl* ctrl, void* user_data);
 	static void onClickModifyStatus(LLUICtrl* ctrl, void* user_data);
 
 	static void handleRemove(S32 option, void* user_data);
-	static void handleModifyRights(S32 option, void* user_data);
+	static void modifyRightsConfirmation(S32 option, void* user_data);
 
 private:
 	// member data
@@ -132,7 +139,6 @@ class LLPanelFriends : public LLPanel, public LLEventTimer
 	LLUUID mAddFriendID;
 	LLString mAddFriendName;
 	LLScrollListCtrl*			mFriendsList;
-	S32		mMenuState;
 	BOOL mShowMaxSelectWarning;
 	BOOL mAllowRightsChange;
 	S32 mNumRightsChanged;
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 0ce91ef7405624c838793b9bbb7d9268569073af..9f1624d20c61c7ea2e6398bed08b618c34d36827 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -262,6 +262,7 @@ void LLFloaterInspect::refresh()
 void LLFloaterInspect::onFocusReceived()
 {
 	gToolMgr->setTransientTool(gToolInspect);
+	LLFloater::onFocusReceived();
 }
 
 void LLFloaterInspect::dirty()
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 3b96a4ce5eb01b494d6bd8c4815c06011c79b5b9..2a352dfc3d95adb0cd0ce6e869c774b59d129cfb 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -1045,8 +1045,10 @@ BOOL LLPanelLandObjects::postBuild()
 	
 	mSelectedObjects = LLUICtrlFactory::getTextBoxByName(this, "selected_objects_text");
 	mCleanOtherObjectsTime = LLUICtrlFactory::getLineEditorByName(this, "clean other time");
-	mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus);
+
+	mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus, this);
 	mCleanOtherObjectsTime->setCommitCallback(onCommitClean);
+
 	childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32);
 	childSetUserData("clean other time", this);
 	
@@ -1135,7 +1137,7 @@ void LLPanelLandObjects::onDoubleClickOwner(void *userdata)
 			return;
 		}
 		// Is this a group?
-		BOOL is_group = cell->getText() == OWNER_GROUP;
+		BOOL is_group = cell->getValue().asString() == OWNER_GROUP;
 		if (is_group)
 		{
 			LLFloaterGroupInfo::showFromUUID(owner_id);
@@ -1180,19 +1182,16 @@ void LLPanelLandObjects::refresh()
 	}
 	else
 	{
-		S32 sw_max = 0;
-		S32 sw_total = 0;
-		S32 max = 0;
-		S32 total = 0;
-		S32 owned = 0;
-		S32 group = 0;
-		S32 other = 0;
-		S32 selected = 0;
-		F32 parcel_object_bonus = 0.f;
-
-		gParcelMgr->getPrimInfo(sw_max, sw_total, 
-								  max, total, owned, group, other, selected,
-								  parcel_object_bonus, mOtherTime);
+		S32 sw_max = parcel->getSimWideMaxPrimCapacity();
+		S32 sw_total = parcel->getSimWidePrimCount();
+		S32 max = llround(parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus());
+		S32 total = parcel->getPrimCount();
+		S32 owned = parcel->getOwnerPrimCount();
+		S32 group = parcel->getGroupPrimCount();
+		S32 other = parcel->getOtherPrimCount();
+		S32 selected = parcel->getSelectedPrimCount();
+		F32 parcel_object_bonus = parcel->getParcelPrimBonus();
+		mOtherTime = parcel->getCleanOtherTime();
 
 		// Can't have more than region max tasks, regardless of parcel
 		// object bonus factor.
@@ -1442,14 +1441,6 @@ void LLPanelLandObjects::onClickReturnOwnerList(void* userdata)
 {
 	LLPanelLandObjects	*self = (LLPanelLandObjects *)userdata;
 
-	S32 sw_max, sw_total;
-	S32 max, total;
-	S32 owned, group, other, selected;
-	F32 parcel_object_bonus;
-	S32 other_time;
-
-	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);
-
 	LLParcel* parcelp = self->mParcel->getParcel();
 	if (!parcelp) return;
 
@@ -1632,11 +1623,11 @@ void LLPanelLandObjects::onCommitList(LLUICtrl* ctrl, void* data)
 			return;
 		}
 		// Is this a group?
-		self->mSelectedIsGroup = cell->getText() == OWNER_GROUP;
+		self->mSelectedIsGroup = cell->getValue().asString() == OWNER_GROUP;
 		cell = item->getColumn(2);
-		self->mSelectedName = cell->getText();
+		self->mSelectedName = cell->getValue().asString();
 		cell = item->getColumn(3);
-		self->mSelectedCount = atoi(cell->getText().c_str());
+		self->mSelectedCount = atoi(cell->getValue().asString().c_str());
 
 		// Set the selection, and enable the return button.
 		self->mSelectedOwners.clear();
@@ -1700,18 +1691,14 @@ void LLPanelLandObjects::onClickShowOtherObjects(void* userdata)
 // static
 void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata)
 {
-	S32 sw_max=0, sw_total=0;
-	S32 max=0, total=0;
-	S32 owned=0, group=0, other=0, selected=0;
-	F32 parcel_object_bonus=0;
-	S32 other_time=0;
-
-	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);
+	S32 owned = 0;
 
 	LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata;
 	LLParcel* parcel = panelp->mParcel->getParcel();
 	if (!parcel) return;
 
+	owned = parcel->getOwnerPrimCount();
+
 	send_parcel_select_objects(parcel->getLocalID(), RT_OWNER);
 
 	LLUUID owner_id = parcel->getOwnerID();
@@ -1739,14 +1726,6 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata)
 // static
 void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata)
 {
-	S32 sw_max=0, sw_total=0;
-	S32 max=0, total=0;
-	S32 owned=0, group=0, other=0, selected=0;
-	F32 parcel_object_bonus=0;
-	S32 other_time=0;
-	
-	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);
-
 	LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata;
 	LLParcel* parcel = panelp->mParcel->getParcel();
 	if (!parcel) return;
@@ -1758,7 +1737,7 @@ void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata)
 	
 	LLStringBase<char>::format_map_t args;
 	args["[NAME]"] = group_name;
-	args["[N]"] = llformat("%d",group);
+	args["[N]"] = llformat("%d", parcel->getGroupPrimCount());
 
 	// create and show confirmation textbox
 	gViewerWindow->alertXml("ReturnObjectsDeededToGroup", args, callbackReturnGroupObjects, userdata);
@@ -1767,17 +1746,13 @@ void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata)
 // static
 void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)
 {
-	S32 sw_max=0, sw_total=0;
-	S32 max=0, total=0;
-	S32 owned=0, group=0, other=0, selected=0;
-	F32 parcel_object_bonus=0;
-	S32 other_time=0;
-
-	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);
+	S32 other = 0;
 
 	LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata;
 	LLParcel* parcel = panelp->mParcel->getParcel();
 	if (!parcel) return;
+	
+	other = parcel->getOtherPrimCount();
 
 	send_parcel_select_objects(parcel->getLocalID(), RT_OTHER);
 
@@ -1817,9 +1792,9 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)
 }
 
 // static
-void LLPanelLandObjects::onLostFocus(LLUICtrl *caller, void* user_data)
+void LLPanelLandObjects::onLostFocus(LLFocusableElement* caller, void* user_data)
 {
-	onCommitClean(caller, user_data);
+	onCommitClean((LLUICtrl*)caller, user_data);
 }
 
 // static
@@ -2408,6 +2383,13 @@ void LLPanelLandMedia::refresh()
 		mCheckSoundLocal->set( parcel->getSoundLocal() );
 		mCheckSoundLocal->setEnabled( can_change_media );
 
+		LLViewerRegion* selection_region = gParcelMgr->getSelectionRegion();
+		BOOL region_allows_voice = FALSE;
+		if (selection_region)
+		{
+			region_allows_voice = selection_region->isVoiceEnabled();
+		}
+
 		if(parcel->getVoiceEnabled())
 		{
 			if(parcel->getVoiceUseEstateChannel())
@@ -2420,7 +2402,7 @@ void LLPanelLandMedia::refresh()
 			mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatDisable);
 		}
 
-		mRadioVoiceChat->setEnabled( can_change_media );
+		mRadioVoiceChat->setEnabled( can_change_media && region_allows_voice );
 
 		// don't display urls if you're not able to change it
 		// much requested change in forums so people can't 'steal' urls
@@ -2535,7 +2517,7 @@ void LLPanelLandMedia::onClickStopMedia ( void* data )
 void LLPanelLandMedia::onClickStartMedia ( void* data )
 {
 	// force a commit
-	gFocusMgr.setKeyboardFocus ( NULL, NULL );
+	gFocusMgr.setKeyboardFocus ( NULL );
 
 	// force a reload
 	LLMediaEngine::getInstance ()->convertImageAndLoadUrl ( true, false, std::string());
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index fa941caf787d8a1df9e47254d66ab25253b87654..4bb88aa127a8ce3a7dd9da93aad3c24038d3b98a 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -257,7 +257,7 @@ class LLPanelLandObjects
 	static void onDoubleClickOwner(void*);	
 
 	static void onCommitList(LLUICtrl* ctrl, void* data);
-	static void onLostFocus(LLUICtrl* caller, void* user_data);
+	static void onLostFocus(LLFocusableElement* caller, void* user_data);
 	static void onCommitClean(LLUICtrl* caller, void* user_data);
 	static void processParcelObjectOwnersReply(LLMessageSystem *msg, void **);
 	
diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index a00f512515fd7a9e5e4bca11192d91d36dcbb6b9..5306ce11b197c1c7bf1337a49b5faf6d51dd752e 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -137,8 +137,7 @@ BOOL LLFloaterPostcard::postBuild()
 		MsgField->setWordWrap(TRUE);
 
 		// For the first time a user focusess to .the msg box, all text will be selected.
-		MsgField->setFocusChangedCallback(onMsgFormFocusRecieved);
-		MsgField->setCallbackUserData(this);
+		MsgField->setFocusChangedCallback(onMsgFormFocusRecieved, this);
 	}
 	
 	childSetFocus("to_form", TRUE);
@@ -347,7 +346,7 @@ void LLFloaterPostcard::updateUserInfo(const char *email)
 	}
 }
 
-void LLFloaterPostcard::onMsgFormFocusRecieved(LLUICtrl* receiver, void* data)
+void LLFloaterPostcard::onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data)
 {
 	LLFloaterPostcard* self = (LLFloaterPostcard *)data;
 	if(self) 
diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h
index 78da8b55d8f1f2993392a5e8286f85159dc4562d..287d34c7061f4dcd4d232ac3af7bbfde3883603c 100644
--- a/indra/newview/llfloaterpostcard.h
+++ b/indra/newview/llfloaterpostcard.h
@@ -65,7 +65,7 @@ class LLFloaterPostcard
 
 	static void updateUserInfo(const char *email);
 
-	static void onMsgFormFocusRecieved(LLUICtrl* receiver, void* data);
+	static void onMsgFormFocusRecieved(LLFocusableElement* receiver, void* data);
 	static void missingSubjMsgAlertCallback(S32 option, void* data);
 
 	void sendPostcard();
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 3306142856a139c0e15ba2b5a5d2f58213dbcf15..eaf7832eabbe8c69c35f954929670b4857214d7f 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -161,50 +161,55 @@ bool estate_dispatch_initialized = false;
 /// LLFloaterRegionInfo
 ///----------------------------------------------------------------------------
 
-LLFloaterRegionInfo* LLFloaterRegionInfo::sInstance = NULL;
 //S32 LLFloaterRegionInfo::sRequestSerial = 0;
 LLUUID LLFloaterRegionInfo::sRequestInvoice;
 
-LLFloaterRegionInfo::LLFloaterRegionInfo(const LLRect& rect) :
-	LLFloater("regioninfo", rect, "Region/Estate")
+LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed)
 {
-	LLRect tr(0, rect.getHeight() - LLFLOATER_HEADER_SIZE, rect.getWidth(), 0);
-	mTab = new LLTabContainer("tab", tr, LLTabContainer::TOP, NULL,NULL,"");
-	mTab->setBorderVisible(FALSE);
-	addChild(mTab);
+	gUICtrlFactory->buildFloater(this, "floater_region_info.xml", NULL, FALSE);
+}
+
+BOOL LLFloaterRegionInfo::postBuild()
+{
+	mTab = gUICtrlFactory->getTabContainerByName(this, "region_panels");
 
 	// contruct the panels
-	LLPanel* panel;
+	LLPanelRegionInfo* panel;
 	panel = new LLPanelRegionGeneralInfo;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_general.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), TRUE);
 
 	panel = new LLPanelRegionDebugInfo;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_debug.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
 
 	panel = new LLPanelRegionTextureInfo;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_texture.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
 
 	panel = new LLPanelRegionTerrainInfo;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_terrain.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
 
 	panel = new LLPanelEstateInfo;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_estate.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
 
 	panel = new LLPanelEstateCovenant;
-	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
+	mInfoPanels.push_back(panel);
 	gUICtrlFactory->buildPanel(panel, "panel_region_covenant.xml");
 	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
 
+	gMessageSystem->setHandlerFunc(
+		"EstateOwnerMessage", 
+		&processEstateOwnerRequest);
+
+	return TRUE;
 }
 
 LLFloaterRegionInfo::~LLFloaterRegionInfo()
@@ -212,23 +217,20 @@ LLFloaterRegionInfo::~LLFloaterRegionInfo()
 	sInstance = NULL;
 }
 
-// static
-void LLFloaterRegionInfo::show(LLViewerRegion* region)
+void LLFloaterRegionInfo::onOpen()
 {
-	if (!sInstance)
-	{
-		LLRect rect = gSavedSettings.getRect("FloaterRegionInfo");
-		S32 left, top;
-		gFloaterView->getNewFloaterPosition(&left, &top);
-		rect.translate(left,top);
-		sInstance = new LLFloaterRegionInfo(rect);
-		gMessageSystem->setHandlerFunc(
-			"EstateOwnerMessage", 
-			&processEstateOwnerRequest);
-	}
-	sInstance->open();		/* Flawfinder: ignore*/
-	sInstance->refreshFromRegion(region);
+	LLRect rect = gSavedSettings.getRect("FloaterRegionInfo");
+	S32 left, top;
+	gFloaterView->getNewFloaterPosition(&left, &top);
+	rect.translate(left,top);
+
+	requestRegionInfo();
+	refreshFromRegion(gAgent.getRegion());
+	LLFloater::onOpen();
+}
 
+void LLFloaterRegionInfo::requestRegionInfo()
+{
 	// Must allow anyone to request the RegionInfo data
 	// so non-owners/non-gods can see the values. 
 	// Therefore can't use an EstateOwnerMessage JC
@@ -241,18 +243,6 @@ void LLFloaterRegionInfo::show(LLViewerRegion* region)
 
 }
 
-// static
-void LLFloaterRegionInfo::show(void*)
-{
-	show(gAgent.getRegion());
-}
-
-// static
-LLFloaterRegionInfo* LLFloaterRegionInfo::getInstance()
-{
-	return sInstance;
-}
-
 // static
 void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**)
 {
@@ -264,7 +254,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**)
 		LLPanelEstateInfo::initDispatch(dispatch);
 	}
 
-	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "tab");
+	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "region_panels");
 	if (!tab) return;
 
 	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab, "Estate");
@@ -293,7 +283,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
 
 	llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl;
 	if(!sInstance) return;
-	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "tab");
+	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "region_panels");
 	if(!tab) return;
 
 	// extract message
@@ -376,7 +366,7 @@ LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate()
 {
 	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
 	if (!floater) return NULL;
-	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
+	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "region_panels");
 	if (!tab) return NULL;
 	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab,"Estate");
 	return panel;
@@ -387,7 +377,7 @@ LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant()
 {
 	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
 	if (!floater) return NULL;
-	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
+	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "region_panels");
 	if (!tab) return NULL;
 	LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)LLUICtrlFactory::getPanelByName(tab, "Covenant");
 	return panel;
@@ -1241,7 +1231,7 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate()
 	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
 	if (!floater) return true;
 
-	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
+	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "region_panels");
 	if (!tab) return true;
 
 	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab, "Estate");
@@ -2803,7 +2793,7 @@ bool LLDispatchSetEstateOwner::operator()(
 	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
 	if (!floater) return true;
 
-	LLTabContainer* tab = (LLTabContainer*)(floater->getChildByName("tab"));
+	LLTabContainer* tab = (LLTabContainer*)(floater->getChildByName("region_panels"));
 	if (!tab) return true;
 
 	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)(tab->getChildByName("Estate"));
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index abf4789b6d808d614f03215fb5e93dd282de092b..6f9ed1fc3447da2dd0f1b458aba7662d06bbaed1 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -58,14 +58,15 @@ class LLPanelRegionTerrainInfo;
 class LLPanelEstateInfo;
 class LLPanelEstateCovenant;
 
-class LLFloaterRegionInfo : public LLFloater
+class LLFloaterRegionInfo : public LLFloater, public LLUISingleton<LLFloaterRegionInfo>
 {
+	friend class LLUISingleton<LLFloaterRegionInfo>;
 public:
 	~LLFloaterRegionInfo();
 
-	static void show(LLViewerRegion* region);
-	static void show(void*);
-	static LLFloaterRegionInfo* getInstance();
+	/*virtual*/ void onOpen();
+	/*virtual*/ BOOL postBuild();
+
 	static void processEstateOwnerRequest(LLMessageSystem* msg, void**);
 
 	// get and process region info if necessary.
@@ -82,15 +83,14 @@ class LLFloaterRegionInfo : public LLFloater
 	// from LLPanel
 	virtual void refresh();
 	
+	void requestRegionInfo();
+
 protected:
-	LLFloaterRegionInfo(const LLRect& rect);
+	LLFloaterRegionInfo(const LLSD& seed);
 	void refreshFromRegion(LLViewerRegion* region);
 
-	// static data
-	static LLFloaterRegionInfo* sInstance;
-
 	// member data
-	LLTabContainer* mTab;
+	LLTabContainerCommon* mTab;
 	typedef std::vector<LLPanelRegionInfo*> info_panels_t;
 	info_panels_t mInfoPanels;
 	//static S32 sRequestSerial;	// serial # of last EstateOwnerRequest
diff --git a/indra/newview/llfloaterscriptdebug.cpp b/indra/newview/llfloaterscriptdebug.cpp
index 9d600befdb60292e1aea877dda2abddc6e2138cb..80a686d1622386e8ad3a0300eccc5b12a56e1557 100644
--- a/indra/newview/llfloaterscriptdebug.cpp
+++ b/indra/newview/llfloaterscriptdebug.cpp
@@ -177,7 +177,7 @@ LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput(const LLUUID& object_id)
 	mHistoryEditor->setWordWrap( TRUE );
 	mHistoryEditor->setFollowsAll();
 	mHistoryEditor->setEnabled( FALSE );
-	mHistoryEditor->setTakesFocus( TRUE );  // We want to be able to cut or copy from the history.
+	mHistoryEditor->setTabStop( TRUE );  // We want to be able to cut or copy from the history.
 	addChild(mHistoryEditor);
 }
 
@@ -200,7 +200,7 @@ void LLFloaterScriptDebugOutput::init(const LLString& title, BOOL resizable,
 	mHistoryEditor->setWordWrap( TRUE );
 	mHistoryEditor->setFollowsAll();
 	mHistoryEditor->setEnabled( FALSE );
-	mHistoryEditor->setTakesFocus( TRUE );  // We want to be able to cut or copy from the history.
+	mHistoryEditor->setTabStop( TRUE );  // We want to be able to cut or copy from the history.
 	addChild(mHistoryEditor);
 }
 
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 22581c6576ae2c75682a484e9d83baa95ccd5b0e..d03ce373cccb220fcda616d0820a96405350926f 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -942,7 +942,7 @@ void commit_select_component(LLUICtrl *ctrl, void *data)
 	//forfeit focus
 	if (gFocusMgr.childHasKeyboardFocus(floaterp))
 	{
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
+		gFocusMgr.setKeyboardFocus(NULL);
 	}
 
 	BOOL select_individuals = floaterp->mCheckSelectIndividual->get();
@@ -992,4 +992,5 @@ void LLFloaterTools::setEditTool(void* tool_pointer)
 void LLFloaterTools::onFocusReceived()
 {
 	gToolMgr->setCurrentToolset(gBasicToolset);
+	LLFloater::onFocusReceived();
 }
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index e3f236beccf1aae0729db63f337528a149bca52c..6bbb748a10696bee460283ca669c74f05bcf65ce 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -257,8 +257,8 @@ void LLFloaterTopObjects::updateSelectionInfo()
 	std::string object_id_string = object_id.asString();
 
 	childSetValue("id_editor", LLSD(object_id_string));
-	childSetValue("object_name_editor", list->getFirstSelected()->getColumn(1)->getText());
-	childSetValue("owner_name_editor", list->getFirstSelected()->getColumn(2)->getText());
+	childSetValue("object_name_editor", list->getFirstSelected()->getColumn(1)->getValue().asString());
+	childSetValue("owner_name_editor", list->getFirstSelected()->getColumn(2)->getValue().asString());
 }
 
 // static
@@ -451,8 +451,8 @@ void LLFloaterTopObjects::showBeacon()
 	LLScrollListItem* first_selected = list->getFirstSelected();
 	if (!first_selected) return;
 
-	LLString name = first_selected->getColumn(1)->getText();
-	LLString pos_string =  first_selected->getColumn(3)->getText();
+	LLString name = first_selected->getColumn(1)->getValue().asString();
+	LLString pos_string =  first_selected->getColumn(3)->getValue().asString();
 
 	F32 x, y, z;
 	S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z);
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 4c03a1561990e1327b70496e4edbf9dd70f1760a..b1bbb341fd890cef331a1f05837e3471c4254600 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -234,7 +234,7 @@ BOOL LLFloaterWorldMap::postBuild()
 
 	childSetAction("DoSearch", onLocationCommit, this);
 
-	childSetFocusChangedCallback("location", updateSearchEnabled);
+	childSetFocusChangedCallback("location", onLocationFocusChanged, this);
 
 	LLLineEditor *location_editor = LLUICtrlFactory::getLineEditorByName(this, "location");
 	if (location_editor)
@@ -1221,6 +1221,12 @@ void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata )
 	}
 }
 
+//static 
+void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus, void* userdata )
+{
+	updateSearchEnabled((LLUICtrl*)focus, userdata);
+}
+
 // static 
 void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata )
 {
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index c069b4092932399364af873eb7c532e9da1ff9cc..6f3c58355776674636c0d08e89a4b8f89c97142d 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -153,6 +153,7 @@ class LLFloaterWorldMap : public LLFloater
 	void			teleportToAvatar();
 
 	static void		updateSearchEnabled( LLUICtrl* ctrl, void* userdata );
+	static void		onLocationFocusChanged( LLFocusableElement* ctrl, void* userdata );
 	static void		onLocationCommit( void* userdata );
 	static void		onCommitLocation( LLUICtrl* ctrl, void* userdata );
 	static void		onCommitSearchResult( LLUICtrl* ctrl, void* userdata );
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index 2577474e243583b951fa5ca81bbef801b12def7c..deffca3b79151d83fb52ed22c87c013b6a5abbcb 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -94,7 +94,7 @@ void copy_selected_item(void* user_data);
 void open_selected_items(void* user_data);
 void properties_selected_items(void* user_data);
 void paste_items(void* user_data);
-void renamer_focus_lost( LLUICtrl* handler, void* user_data );
+void renamer_focus_lost( LLFocusableElement* handler, void* user_data );
 
 ///----------------------------------------------------------------------------
 /// Class LLFolderViewItem
@@ -693,7 +693,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
 					// Release keyboard focus, so that if stuff is dropped into the
 					// world, pressing the delete key won't blow away the inventory
 					// item.
-					gViewerWindow->setKeyboardFocus(NULL, NULL);
+					gViewerWindow->setKeyboardFocus(NULL);
 
 					return gToolDragAndDrop->handleHover( x, y, mask );
 				}
@@ -3164,7 +3164,7 @@ void LLFolderView::draw()
 	}
 	if(gViewerWindow->hasKeyboardFocus(this) && !getVisible())
 	{
-		gViewerWindow->setKeyboardFocus( NULL, NULL );
+		gViewerWindow->setKeyboardFocus( NULL );
 	}
 
 	// while dragging, update selection rendering to reflect single/multi drag status
@@ -3656,7 +3656,7 @@ void LLFolderView::startRenamingSelectedItem( void )
 		mRenamer->setVisible( TRUE );
 		// set focus will fail unless item is visible
 		mRenamer->setFocus( TRUE );
-		mRenamer->setFocusLostCallback(renamer_focus_lost);
+		mRenamer->setLostTopCallback(onRenamerLost);
 		gViewerWindow->setTopCtrl( mRenamer );
 	}
 }
@@ -3730,7 +3730,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 			{
 				if( gViewerWindow->childHasKeyboardFocus( this ) )
 				{
-					gViewerWindow->setKeyboardFocus( NULL, NULL );
+					gViewerWindow->setKeyboardFocus( NULL );
 				}
 			}
 			mSearchString.clear();
@@ -4438,12 +4438,10 @@ bool LLInventorySort::operator()(LLFolderViewItem* a, LLFolderViewItem* b)
 	}
 }
 
-void renamer_focus_lost( LLUICtrl* ctrl, void* userdata)
+//static 
+void LLFolderView::onRenamerLost( LLUICtrl* renamer, void* user_data)
 {
-	if( ctrl ) 
-	{
-		ctrl->setVisible( FALSE );
-	}
+	renamer->setVisible(FALSE);
 }
 
 void delete_selected_item(void* user_data)
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index dd0dd21705ba4175af5a02e1b9aed45aa996a98d..9fcf94d802407e982aa4b556fb0eb2aa2a485e98 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -876,6 +876,8 @@ class LLFolderView : public LLFolderViewFolder, LLEditMenuHandler
 	LLScrollableContainerView* mScrollContainer;  // NULL if this is not a child of a scroll container.
 
 	static void commitRename( LLUICtrl* renamer, void* user_data );
+	static void onRenamerLost( LLUICtrl* renamer, void* user_data);
+
 	void finishRenamingItem( void );
 	void revertRenamingItem( void );
 
diff --git a/indra/newview/llhudview.cpp b/indra/newview/llhudview.cpp
index e40e84b9da1bfc623062f426ec7476751002b753..7f549bb2eb664a409d308e281ed5d4434a5fa85f 100644
--- a/indra/newview/llhudview.cpp
+++ b/indra/newview/llhudview.cpp
@@ -52,8 +52,8 @@ LLHUDView *gHUDView = NULL;
 
 const S32 HUD_ARROW_SIZE = 32;
 
-LLHUDView::LLHUDView(const std::string& name, const LLRect& rect)
-:	LLView(name, rect, FALSE)
+LLHUDView::LLHUDView()
+:	LLPanel()
 { }
 
 LLHUDView::~LLHUDView()
diff --git a/indra/newview/llhudview.h b/indra/newview/llhudview.h
index b2353ad5df669fe790cf2183013cc7bd2cf866b6..cbefdc121e0c1a43f05e45a015165e8499be25ee 100644
--- a/indra/newview/llhudview.h
+++ b/indra/newview/llhudview.h
@@ -32,16 +32,16 @@
 #ifndef LL_LLHUDVIEW_H
 #define LL_LLHUDVIEW_H
 
-#include "llview.h"
+#include "llpanel.h"
 #include "v4color.h"
 
 class LLVector3d;
 
 class LLHUDView
-: public LLView
+: public LLPanel
 {
 public:
-	LLHUDView(const std::string& name, const LLRect& rect);
+	LLHUDView();
 	virtual ~LLHUDView();
 
 	virtual EWidgetType getWidgetType() const;
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 810d3a26a164e05b2a975a02d1c1c9178bbf2e3c..b1fefc4f5d86c49b658be480223d22e42af83ee6 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -63,6 +63,7 @@
 #include "llviewerstats.h"
 #include "llviewercontrol.h"
 #include "llvieweruictrlfactory.h"
+#include "llviewerwindow.h"
 #include "lllogchat.h"
 #include "llfloaterhtml.h"
 #include "llweb.h"
@@ -92,10 +93,14 @@ static LLString sSessionStartString = "Starting session with [NAME] please wait.
 LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
 LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
 LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
+LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
 
-void session_starter_helper(const LLUUID& temp_session_id,
-							const LLUUID& other_participant_id,
-							EInstantMessage im_type)
+BOOL LLVoiceChannel::sSuspended = FALSE;
+
+void session_starter_helper(
+	const LLUUID& temp_session_id,
+	const LLUUID& other_participant_id,
+	EInstantMessage im_type)
 {
 	LLMessageSystem *msg = gMessageSystem;
 
@@ -122,47 +127,111 @@ void session_starter_helper(const LLUUID& temp_session_id,
 	msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
 }
 
+void start_deprecated_conference_chat(
+	const LLUUID& temp_session_id,
+	const LLUUID& creator_id,
+	const LLUUID& other_participant_id,
+	const LLSD& agents_to_invite)
+{
+	U8* bucket;
+	U8* pos;
+	S32 count;
+	S32 bucket_size;
+
+	// *FIX: this could suffer from endian issues
+	count = agents_to_invite.size();
+	bucket_size = UUID_BYTES * count;
+	bucket = new U8[bucket_size];
+	pos = bucket;
+
+	for(S32 i = 0; i < count; ++i)
+	{
+		LLUUID agent_id = agents_to_invite[i].asUUID();
+		
+		memcpy(pos, &agent_id, UUID_BYTES);
+		pos += UUID_BYTES;
+	}
+
+	session_starter_helper(
+		temp_session_id,
+		other_participant_id,
+		IM_SESSION_CONFERENCE_START);
+
+	gMessageSystem->addBinaryDataFast(
+		_PREHASH_BinaryBucket,
+		bucket,
+		bucket_size);
+
+	gAgent.sendReliableMessage();
+ 
+	delete[] bucket;
+}
+
+class LLStartConferenceChatResponder : public LLHTTPClient::Responder
+{
+public:
+	LLStartConferenceChatResponder(
+		const LLUUID& temp_session_id,
+		const LLUUID& creator_id,
+		const LLUUID& other_participant_id,
+		const LLSD& agents_to_invite)
+	{
+		mTempSessionID = temp_session_id;
+		mCreatorID = creator_id;
+		mOtherParticipantID = other_participant_id;
+		mAgents = agents_to_invite;
+	}
+
+	virtual void error(U32 statusNum, const std::string& reason)
+	{
+		//try an "old school" way.
+		if ( statusNum == 400 )
+		{
+			start_deprecated_conference_chat(
+				mTempSessionID,
+				mCreatorID,
+				mOtherParticipantID,
+				mAgents);
+		}
+
+		//else throw an error back to the client?
+		//in theory we should have just have these error strings
+		//etc. set up in this file as opposed to the IMMgr,
+		//but the error string were unneeded here previously
+		//and it is not worth the effort switching over all
+		//the possible different language translations
+	}
+
+private:
+	LLUUID mTempSessionID;
+	LLUUID mCreatorID;
+	LLUUID mOtherParticipantID;
+
+	LLSD mAgents;
+};
+
 // Returns true if any messages were sent, false otherwise.
 // Is sort of equivalent to "does the server need to do anything?"
-bool send_start_session_messages(const LLUUID& temp_session_id,
-								 const LLUUID& other_participant_id,
-								 const LLDynamicArray<LLUUID>& ids,
-								 EInstantMessage dialog)
+bool send_start_session_messages(
+	const LLUUID& temp_session_id,
+	const LLUUID& other_participant_id,
+	const LLDynamicArray<LLUUID>& ids,
+	EInstantMessage dialog)
 {
-	if ( (dialog == IM_SESSION_GROUP_START) ||
-		 (dialog == IM_SESSION_CONFERENCE_START) )
+	if ( dialog == IM_SESSION_GROUP_START )
 	{
-		S32 count = ids.size();
-		S32 bucket_size = UUID_BYTES * count;
-		U8* bucket;
-		U8* pos;
-
-		session_starter_helper(temp_session_id,
-							   other_participant_id,
-							   dialog);
+		session_starter_helper(
+			temp_session_id,
+			other_participant_id,
+			dialog);
 
 		switch(dialog)
 		{
 		case IM_SESSION_GROUP_START:
-			gMessageSystem->addBinaryDataFast(_PREHASH_BinaryBucket,
-											  EMPTY_BINARY_BUCKET,
-											  EMPTY_BINARY_BUCKET_SIZE);
-			break;
-		case IM_SESSION_CONFERENCE_START:
-			bucket = new U8[bucket_size];
-			pos = bucket;
-
-			// *FIX: this could suffer from endian issues
-			for(S32 i = 0; i < count; ++i)
-			{
-				memcpy(pos, &(ids.get(i)), UUID_BYTES);
-				pos += UUID_BYTES;
-			}
-			gMessageSystem->addBinaryDataFast(_PREHASH_BinaryBucket,
-											  bucket,
-											  bucket_size);
-			delete[] bucket;
-
+			gMessageSystem->addBinaryDataFast(
+				_PREHASH_BinaryBucket,
+				EMPTY_BINARY_BUCKET,
+				EMPTY_BINARY_BUCKET_SIZE);
 			break;
 		default:
 			break;
@@ -171,6 +240,44 @@ bool send_start_session_messages(const LLUUID& temp_session_id,
 
 		return true;
 	}
+	else if ( dialog == IM_SESSION_CONFERENCE_START )
+	{
+		LLSD agents;
+		for (int i = 0; i < (S32) ids.size(); i++)
+		{
+			agents.append(ids.get(i));
+		}
+
+		//we have a new way of starting conference calls now
+		LLViewerRegion* region = gAgent.getRegion();
+		if (region)
+		{
+			std::string url = region->getCapability(
+				"ChatSessionRequest");
+			LLSD data;
+			data["method"] = "start conference";
+			data["session-id"] = temp_session_id;
+
+			data["params"] = agents;
+
+			LLHTTPClient::post(
+				url,
+				data,
+				new LLStartConferenceChatResponder(
+					temp_session_id,
+					gAgent.getID(),
+					other_participant_id,
+					data["params"]));
+		}
+		else
+		{
+			start_deprecated_conference_chat(
+				temp_session_id,
+				gAgent.getID(),
+				other_participant_id,
+				agents);
+		}
+	}
 
 	return false;
 }
@@ -194,8 +301,20 @@ void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
 		<< status << ": " << reason << ")"
 		<< llendl;
 	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
-	if (channelp)
+	if ( channelp )
 	{
+		if ( 403 == status )
+		{
+			LLNotifyBox::showXml(
+				"VoiceNotAllowed",
+				channelp->getNotifyArgs());
+		}
+		else
+		{
+			LLNotifyBox::showXml(
+				"VoiceCallGenericError",
+				channelp->getNotifyArgs());
+		}
 		channelp->deactivate();
 	}
 }
@@ -242,10 +361,6 @@ LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const LLString& session
 
 LLVoiceChannel::~LLVoiceChannel()
 {
-	// CANNOT do this here, since it will crash on quit in the LLVoiceChannelProximal singleton destructor.
-	// Do it in all other subclass destructors instead.
-	// deactivate();
-	
 	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
 	if(gVoiceClient)
 	{
@@ -266,7 +381,19 @@ void LLVoiceChannel::setChannelInfo(
 
 	if (mState == STATE_NO_CHANNEL_INFO)
 	{
-		if(!mURI.empty() && !mCredentials.empty())
+		if (mURI.empty())
+		{
+			LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs);
+			llwarns << "Received empty URI for channel " << mSessionName << llendl;
+			deactivate();
+		}
+		else if (mCredentials.empty())
+		{
+			LLNotifyBox::showXml("VoiceChannelJoinFailed", mNotifyArgs);
+			llwarns << "Received empty credentials for channel " << mSessionName << llendl;
+			deactivate();
+		}
+		else
 		{
 			setState(STATE_READY);
 
@@ -279,12 +406,6 @@ void LLVoiceChannel::setChannelInfo(
 				activate();
 			}
 		}
-		else
-		{
-			//*TODO: notify user
-			llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
-			deactivate();
-		}
 	}
 }
 
@@ -325,7 +446,7 @@ void LLVoiceChannel::handleStatusChange(EStatusType type)
 		}
 		break;
 	case STATUS_LEFT_CHANNEL:
-		if (callStarted() && !mIgnoreNextSessionLeave)
+		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
 		{
 			// if forceably removed from channel
 			// update the UI and revert to default channel
@@ -496,6 +617,38 @@ void LLVoiceChannel::initClass()
 	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
 }
 
+
+//static 
+void LLVoiceChannel::suspend()
+{
+	if (!sSuspended)
+	{
+		sSuspendedVoiceChannel = sCurrentVoiceChannel;
+		sSuspended = TRUE;
+	}
+}
+
+//static 
+void LLVoiceChannel::resume()
+{
+	if (sSuspended)
+	{
+		if (gVoiceClient->voiceEnabled())
+		{
+			if (sSuspendedVoiceChannel)
+			{
+				sSuspendedVoiceChannel->activate();
+			}
+			else
+			{
+				LLVoiceChannelProximal::getInstance()->activate();
+			}
+		}
+		sSuspended = FALSE;
+	}
+}
+
+
 //
 // LLVoiceChannelGroup
 //
@@ -507,11 +660,6 @@ LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const LLStrin
 	mIsRetrying = FALSE;
 }
 
-LLVoiceChannelGroup::~LLVoiceChannelGroup()
-{
-	deactivate();
-}
-
 void LLVoiceChannelGroup::deactivate()
 {
 	if (callStarted())
@@ -635,6 +783,7 @@ void LLVoiceChannelGroup::handleError(EStatusType status)
 		}
 
 		break;
+
 	case ERROR_UNKNOWN:
 	default:
 		break;
@@ -677,11 +826,6 @@ LLVoiceChannelProximal::LLVoiceChannelProximal() :
 	activate();
 }
 
-LLVoiceChannelProximal::~LLVoiceChannelProximal()
-{
-	// DO NOT call deactivate() here, since this will only happen at atexit() time.	
-}
-
 BOOL LLVoiceChannelProximal::isActive()
 {
 	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel(); 
@@ -725,6 +869,9 @@ void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
 	case STATUS_LEFT_CHANNEL:
 		// do not notify user when leaving proximal channel
 		return;
+	case STATUS_VOICE_DISABLED:
+		 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
+		return;
 	default:
 		break;
 	}
@@ -762,29 +909,26 @@ void LLVoiceChannelProximal::deactivate()
 	}
 }
 
+
 //
 // LLVoiceChannelP2P
 //
 LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const LLString& session_name, const LLUUID& other_user_id) : 
 		LLVoiceChannelGroup(session_id, session_name), 
-		mOtherUserID(other_user_id)
+		mOtherUserID(other_user_id),
+		mReceivedCall(FALSE)
 {
 	// make sure URI reflects encoded version of other user's agent id
 	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
 }
 
-LLVoiceChannelP2P::~LLVoiceChannelP2P() 
-{
-	deactivate();
-}
-
 void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
 {
 	// status updates
 	switch(type)
 	{
 	case STATUS_LEFT_CHANNEL:
-		if (callStarted() && !mIgnoreNextSessionLeave)
+		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
 		{
 			if (mState == STATE_RINGING)
 			{
@@ -832,6 +976,7 @@ void LLVoiceChannelP2P::activate()
 		// no session handle yet, we're starting the call
 		if (mSessionHandle.empty())
 		{
+			mReceivedCall = FALSE;
 			LLVoiceClient::getInstance()->callUser(mOtherUserID);
 		}
 		// otherwise answering the call
@@ -879,24 +1024,37 @@ void LLVoiceChannelP2P::setSessionHandle(const LLString& handle)
 	mSessionHandle = handle;
 	// The URI of a p2p session should always be the other end's SIP URI.
 	setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
-	
+	mReceivedCall = TRUE;
+
 	if (needs_activate)
 	{
 		activate();
 	}
 }
 
+void LLVoiceChannelP2P::setState(EState state)
+{
+	// you only "answer" voice invites in p2p mode
+	// so provide a special purpose message here
+	if (mReceivedCall && state == STATE_RINGING)
+	{
+		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
+		mState = state;
+		return;
+	}
+	LLVoiceChannel::setState(state);
+}
+
+
 //
 // LLFloaterIMPanel
 //
 LLFloaterIMPanel::LLFloaterIMPanel(
-	const std::string& name,
-	const LLRect& rect,
 	const std::string& session_label,
 	const LLUUID& session_id,
 	const LLUUID& other_participant_id,
 	EInstantMessage dialog) :
-	LLFloater(name, rect, session_label),
+	LLFloater(session_label, LLRect(), session_label),
 	mInputEditor(NULL),
 	mHistoryEditor(NULL),
 	mSessionUUID(session_id),
@@ -909,6 +1067,7 @@ LLFloaterIMPanel::LLFloaterIMPanel(
 	mOtherTyping(FALSE),
 	mTypingLineStartIndex(0),
 	mSentTypingState(TRUE),
+	mNumUnreadMessages(0),
 	mShowSpeakersOnConnect(TRUE),
 	mAutoConnect(FALSE),
 	mSpeakerPanel(NULL),
@@ -919,14 +1078,12 @@ LLFloaterIMPanel::LLFloaterIMPanel(
 }
 
 LLFloaterIMPanel::LLFloaterIMPanel(
-	const std::string& name,
-	const LLRect& rect,
 	const std::string& session_label,
 	const LLUUID& session_id,
 	const LLUUID& other_participant_id,
 	const LLDynamicArray<LLUUID>& ids,
 	EInstantMessage dialog) :
-	LLFloater(name, rect, session_label),
+	LLFloater(session_label, LLRect(), session_label),
 	mInputEditor(NULL),
 	mHistoryEditor(NULL),
 	mSessionUUID(session_id),
@@ -952,13 +1109,15 @@ LLFloaterIMPanel::LLFloaterIMPanel(
 
 void LLFloaterIMPanel::init(const LLString& session_label)
 {
+	mSessionLabel = session_label;
+
 	LLString xml_filename;
 	switch(mDialog)
 	{
 	case IM_SESSION_GROUP_START:
 		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
 		xml_filename = "floater_instant_message_group.xml";
-		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label);
+		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
 		break;
 	case IM_SESSION_INVITE:
 		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
@@ -970,21 +1129,21 @@ void LLFloaterIMPanel::init(const LLString& session_label)
 		{
 			xml_filename = "floater_instant_message_ad_hoc.xml";
 		}
-		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label);
+		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
 		break;
 	case IM_SESSION_P2P_INVITE:
 		xml_filename = "floater_instant_message.xml";
-		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, session_label, mOtherParticipantUUID);
+		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID);
 		break;
 	case IM_SESSION_CONFERENCE_START:
 		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
 		xml_filename = "floater_instant_message_ad_hoc.xml";
-		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, session_label);
+		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel);
 		break;
 	// just received text from another user
 	case IM_NOTHING_SPECIAL:
 		xml_filename = "floater_instant_message.xml";
-		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, session_label, mOtherParticipantUUID);
+		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID);
 		break;
 	default:
 		llwarns << "Unknown session type" << llendl;
@@ -999,15 +1158,14 @@ void LLFloaterIMPanel::init(const LLString& session_label)
 								&getFactoryMap(),
 								FALSE);
 
-	setLabel(session_label);
-	setTitle(session_label);
+	setTitle(mSessionLabel);
 	mInputEditor->setMaxTextLength(1023);
 	// enable line history support for instant message bar
 	mInputEditor->setEnableLineHistory(TRUE);
 
 	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
 	{
-		LLLogChat::loadHistory(session_label,
+		LLLogChat::loadHistory(mSessionLabel,
 				       &chatFromLogFile,
 				       (void *)this);
 	}
@@ -1060,16 +1218,12 @@ BOOL LLFloaterIMPanel::postBuild()
 {
 	requires("chat_editor", WIDGET_TYPE_LINE_EDITOR);
 	requires("im_history", WIDGET_TYPE_TEXT_EDITOR);
-	requires("live_help_dialog", WIDGET_TYPE_TEXT_BOX);
-	requires("title_string", WIDGET_TYPE_TEXT_BOX);
-	requires("typing_start_string", WIDGET_TYPE_TEXT_BOX);
-	requires("session_start_string", WIDGET_TYPE_TEXT_BOX);
 
 	if (checkRequirements())
 	{
 		mInputEditor = LLUICtrlFactory::getLineEditorByName(this, "chat_editor");
-		mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived );
-		mInputEditor->setFocusLostCallback( onInputEditorFocusLost );
+		mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this );
+		mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this );
 		mInputEditor->setKeystrokeCallback( onInputEditorKeystroke );
 		mInputEditor->setCommitCallback( onCommitChat );
 		mInputEditor->setCallbackUserData(this);
@@ -1084,6 +1238,7 @@ BOOL LLFloaterIMPanel::postBuild()
 		childSetAction("send_btn", onClickSend, this);
 		childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this);
 
+		childSetAction("moderator_kick_speaker", onKickSpeaker, this);
 		//LLButton* close_btn = LLUICtrlFactory::getButtonByName(this, "close_btn");
 		//close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this);
 
@@ -1094,17 +1249,11 @@ BOOL LLFloaterIMPanel::postBuild()
 		{
 			childSetEnabled("profile_btn", FALSE);
 		}
-		LLTextBox* title = LLUICtrlFactory::getTextBoxByName(this, "title_string");
-		sTitleString = title->getText();
-		
-		LLTextBox* typing_start = LLUICtrlFactory::getTextBoxByName(this, "typing_start_string");
-				
-		sTypingStartString = typing_start->getText();
-
-		LLTextBox* session_start = LLUICtrlFactory::getTextBoxByName(
-			this,
-			"session_start_string");
-		sSessionStartString = session_start->getText();
+
+		sTitleString = getFormattedUIString("title_string");
+		sTypingStartString = getFormattedUIString("typing_start_string");
+		sSessionStartString = getFormattedUIString("session_start_string");
+
 		if (mSpeakerPanel)
 		{
 			mSpeakerPanel->refreshSpeakers();
@@ -1112,7 +1261,7 @@ BOOL LLFloaterIMPanel::postBuild()
 
 		if (mDialog == IM_NOTHING_SPECIAL)
 		{
-			childSetCommitCallback("mute_btn", onClickMuteVoice, this);
+			childSetAction("mute_btn", onClickMuteVoice, this);
 			childSetCommitCallback("speaker_volume", onVolumeChange, this);
 		}
 
@@ -1131,7 +1280,7 @@ void* LLFloaterIMPanel::createSpeakersPanel(void* data)
 }
 
 //static 
-void LLFloaterIMPanel::onClickMuteVoice(LLUICtrl* source, void* user_data)
+void LLFloaterIMPanel::onClickMuteVoice(void* user_data)
 {
 	LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data;
 	if (floaterp)
@@ -1171,10 +1320,22 @@ void LLFloaterIMPanel::draw()
 					  && LLVoiceClient::voiceEnabled();
 
 	// hide/show start call and end call buttons
-	childSetVisible("end_call_btn", mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
-	childSetVisible("start_call_btn", mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
+	childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
+	childSetVisible("start_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
 	childSetEnabled("start_call_btn", enable_connect);
 	childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty());
+	
+	LLPointer<LLSpeaker> self_speaker = mSpeakers->findSpeaker(gAgent.getID());
+	if (self_speaker.notNull() && self_speaker->mModeratorMutedText)
+	{
+		mInputEditor->setEnabled(FALSE);
+		mInputEditor->setLabel(getFormattedUIString("muted_text_label"));
+	}
+	else
+	{
+		mInputEditor->setEnabled(TRUE);
+		mInputEditor->setLabel(getFormattedUIString("default_text_label"));
+	}
 
 	if (mAutoConnect && enable_connect)
 	{
@@ -1215,11 +1376,11 @@ void LLFloaterIMPanel::draw()
 	else
 	{
 		// refresh volume and mute checkbox
-		childSetEnabled("speaker_volume", mVoiceChannel->isActive());
+		childSetVisible("speaker_volume", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
 		childSetValue("speaker_volume", gVoiceClient->getUserVolume(mOtherParticipantUUID));
 
 		childSetValue("mute_btn", gMuteListp->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat));
-		childSetEnabled("mute_btn", mVoiceChannel->isActive());
+		childSetVisible("mute_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
 	}
 	LLFloater::draw();
 }
@@ -1235,7 +1396,6 @@ class LLSessionInviteResponder : public LLHTTPClient::Responder
 	void error(U32 statusNum, const std::string& reason)
 	{
 		llinfos << "Error inviting all agents to session" << llendl;
-
 		//throw something back to the viewer here?
 	}
 
@@ -1243,6 +1403,48 @@ class LLSessionInviteResponder : public LLHTTPClient::Responder
 	LLUUID mSessionID;
 };
 
+class LLSessionImmediateInviteResponder : public LLHTTPClient::Responder
+{
+public:
+	LLSessionImmediateInviteResponder(
+		const LLUUID& session_id,
+		const std::string& chat_req_url,
+		const LLSD& post_data)
+	{
+		mSessionID = session_id;
+		mURL = chat_req_url;
+		mPostData = post_data;
+	}
+
+	void error(U32 statusNum, const std::string& reason)
+	{		
+		if ( statusNum == 400 )
+		{
+			//hrm 400 indicates invalid parameters...more
+			//than likely the method doesn't exist
+			//so try a soon to be deprecated old school way of doing this
+			mPostData["method"] = "invite";
+
+			LLHTTPClient::post(
+				mURL,
+				mPostData,
+				new LLSessionInviteResponder(mSessionID));
+		}
+		else
+		{
+			//throw something back to the viewer here?
+			llinfos << "Error inviting all agents to session" << llendl;
+		}
+	}
+
+private:
+	LLUUID mSessionID;
+	LLSD mPostData;
+
+	std::string mURL;
+};
+
+
 BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
 {
 	LLViewerRegion* region = gAgent.getRegion();
@@ -1267,12 +1469,15 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
 			data["params"].append(ids.get(i));
 		}
 
-		data["method"] = "invite";
+		data["method"] = "immediate invite";
 		data["session-id"] = mSessionUUID;
 		LLHTTPClient::post(
 			url,
 			data,
-			new LLSessionInviteResponder(mSessionUUID));
+			new LLSessionImmediateInviteResponder(
+				mSessionUUID,
+				url,
+				data));
 		
 	}
 	else
@@ -1289,6 +1494,15 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray<LLUUID>& ids)
 
 void LLFloaterIMPanel::addHistoryLine(const LLUUID& source, const std::string &utf8msg, const LLColor4& color, bool log_to_file)
 {
+	// start tab flashing when receiving im for background session from user
+	LLMultiFloater* hostp = getHost();
+	if( !isInVisibleChain() 
+		&& hostp 
+		&& source != gAgent.getID())
+	{
+		hostp->setFloaterFlashing(this, TRUE);
+	}
+
 	addHistoryLine(utf8msg, color, log_to_file);
 	mSpeakers->speakerChatted(source);
 	mSpeakers->setSpeakerTyping(source, FALSE);
@@ -1296,14 +1510,6 @@ void LLFloaterIMPanel::addHistoryLine(const LLUUID& source, const std::string &u
 
 void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file)
 {
-	LLMultiFloater* hostp = getHost();
-	if( !getVisible() && hostp && log_to_file)
-	{
-		// Only flash for logged ("real") messages
-		LLTabContainer* parent = (LLTabContainer*) getParent();
-		parent->setTabPanelFlashing( this, TRUE );
-	}
-
 	// Now we're adding the actual line of text, so erase the 
 	// "Foo is typing..." text segment, and the optional timestamp
 	// if it was present. JC
@@ -1330,6 +1536,11 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
 
 		LLLogChat::saveHistory(getTitle(),histstr);
 	}
+
+	if (!isInVisibleChain())
+	{
+		mNumUnreadMessages++;
+	}
 }
 
 
@@ -1340,10 +1551,7 @@ void LLFloaterIMPanel::setVisible(BOOL b)
 	LLMultiFloater* hostp = getHost();
 	if( b && hostp )
 	{
-		LLTabContainer* parent = (LLTabContainer*) getParent();
-
-		// When this tab is displayed, you can stop flashing.
-		parent->setTabPanelFlashing( this, FALSE );
+		hostp->setFloaterFlashing(this, FALSE);
 
 		/* Don't change containing floater title - leave it "Instant Message" JC
 		LLUIString title = sTitleString;
@@ -1392,7 +1600,7 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask, BOOL called_from_paren
 		else if ( KEY_ESCAPE == key )
 		{
 			handled = TRUE;
-			gFocusMgr.setKeyboardFocus(NULL, NULL);
+			gFocusMgr.setKeyboardFocus(NULL);
 
 			// Close talk panel with escape
 			if( !gSavedSettings.getBOOL("PinTalkViewOpen") )
@@ -1573,14 +1781,14 @@ void LLFloaterIMPanel::onCommitChat(LLUICtrl* caller, void* userdata)
 }
 
 // static
-void LLFloaterIMPanel::onInputEditorFocusReceived( LLUICtrl* caller, void* userdata )
+void LLFloaterIMPanel::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata )
 {
 	LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata;
 	self->mHistoryEditor->setCursorAndScrollToEnd();
 }
 
 // static
-void LLFloaterIMPanel::onInputEditorFocusLost(LLUICtrl* caller, void* userdata)
+void LLFloaterIMPanel::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)
 {
 	LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
 	self->setTyping(FALSE);
@@ -1628,6 +1836,14 @@ void LLFloaterIMPanel::onClose(bool app_quitting)
 	destroy();
 }
 
+void LLFloaterIMPanel::onVisibilityChange(BOOL new_visibility)
+{
+	if (new_visibility)
+	{
+		mNumUnreadMessages = 0;
+	}
+}
+
 void deliver_message(const std::string& utf8_text,
 					 const LLUUID& im_session_id,
 					 const LLUUID& other_participant_id,
@@ -1739,19 +1955,37 @@ void LLFloaterIMPanel::sendMsg()
 	mSentTypingState = TRUE;
 }
 
-void LLFloaterIMPanel::updateSpeakersList(LLSD speaker_updates)
-{ 
-	mSpeakers->processSpeakerListUpdate(speaker_updates); 
+void LLFloaterIMPanel::updateSpeakersList(const LLSD& speaker_updates)
+{
+	mSpeakers->updateSpeakers(speaker_updates); 
 }
 
-void LLFloaterIMPanel::setSpeakersListFromMap(LLSD speaker_map)
+void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update)
 {
-	mSpeakers->processSpeakerMap(speaker_map);
+	if (
+		session_update.has("moderated_mode") &&
+		session_update["moderated_mode"].has("voice") )
+	{
+		BOOL voice_moderated = session_update["moderated_mode"]["voice"];
+
+		if (voice_moderated)
+		{
+			setTitle(mSessionLabel + LLString(" ") + getFormattedUIString("moderated_chat_label"));
+		}
+		else
+		{
+			setTitle(mSessionLabel);
+		}
+
+
+		//update the speakers dropdown too
+		mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated);
+	}
 }
 
-void LLFloaterIMPanel::setSpeakersList(LLSD speaker_list)
+void LLFloaterIMPanel::setSpeakers(const LLSD& speaker_list)
 {
-	mSpeakers->processSpeakerList(speaker_list);
+	mSpeakers->setSpeakers(speaker_list);
 }
 
 void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id)
@@ -1897,5 +2131,77 @@ void LLFloaterIMPanel::chatFromLogFile(LLString line, void* userdata)
 	
 	//self->addHistoryLine(line, LLColor4::grey, FALSE);
 	self->mHistoryEditor->appendColoredText(line, false, true, LLColor4::grey);
+}
+
+void LLFloaterIMPanel::showSessionStartError(
+	const std::string& error_string)
+{
+	//the error strings etc. should be really be static and local
+	//to this file instead of in the LLFloaterIM
+	//but they were in llimview.cpp first and unfortunately
+	//some translations into non English languages already occurred
+	//thus making it a tad harder to change over to a
+	//"correct" solution.  The best solution
+	//would be to store all of the misc. strings into
+	//their own XML file which would be read in by any LLIMPanel
+	//post build function instead of repeating the same info
+	//in the group, adhoc and normal IM xml files.
+	LLString::format_map_t args;
+	args["[REASON]"] =
+		LLFloaterIM::sErrorStringsMap[error_string];
+	args["[RECIPIENT]"] = getTitle();
 
+	gViewerWindow->alertXml(
+		"ChatterBoxSessionStartError",
+		args,
+		onConfirmForceCloseError,
+		this);
 }
+
+void LLFloaterIMPanel::showSessionEventError(
+	const std::string& event_string,
+	const std::string& error_string)
+{
+	LLString::format_map_t args;
+	args["[REASON]"] = 
+		LLFloaterIM::sErrorStringsMap[error_string];
+	args["[EVENT]"] =
+		LLFloaterIM::sEventStringsMap[event_string];
+	args["[RECIPIENT]"] = getTitle();
+
+	gViewerWindow->alertXml(
+		"ChatterBoxSessionEventError",
+		args);
+}
+
+void LLFloaterIMPanel::showSessionForceClose(
+	const std::string& reason_string)
+{
+	LLString::format_map_t args;
+
+	args["[NAME]"] = getTitle();
+	args["[REASON]"] = LLFloaterIM::sForceCloseSessionMap[reason_string];
+
+	gViewerWindow->alertXml(
+		"ForceCloseChatterBoxSession",
+		args,
+		LLFloaterIMPanel::onConfirmForceCloseError,
+		this);
+
+}
+
+//static 
+void LLFloaterIMPanel::onKickSpeaker(void* user_data)
+{
+
+}
+
+void LLFloaterIMPanel::onConfirmForceCloseError(S32 option, void* data)
+{
+	//only 1 option really
+	LLFloaterIMPanel* floater = ((LLFloaterIMPanel*) data);
+
+	if ( floater ) floater->close(FALSE);
+}
+
+
diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h
index c1ad18dd3c562e44674cc42ad73e6c32b7f55819..ef36ff4a33bc5e92731333ccdcf34510c5924ee9 100644
--- a/indra/newview/llimpanel.h
+++ b/indra/newview/llimpanel.h
@@ -74,14 +74,20 @@ class LLVoiceChannel : public LLVoiceClientStatusObserver
 	virtual void getChannelInfo();
 	virtual BOOL isActive();
 	virtual BOOL callStarted();
+
+	const LLUUID getSessionID() { return mSessionID; }
 	EState getState() { return mState; }
 
 	void updateSessionID(const LLUUID& new_session_id);
+	const LLString::format_map_t& getNotifyArgs() { return mNotifyArgs; }
 
 	static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
 	static LLVoiceChannel* getChannelByURI(LLString uri);
 	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }
 	static void initClass();
+	
+	static void suspend();
+	static void resume();
 
 protected:
 	virtual void setState(EState state);
@@ -103,13 +109,14 @@ class LLVoiceChannel : public LLVoiceClientStatusObserver
 	static voice_channel_map_uri_t sVoiceChannelURIMap;
 
 	static LLVoiceChannel* sCurrentVoiceChannel;
+	static LLVoiceChannel* sSuspendedVoiceChannel;
+	static BOOL sSuspended;
 };
 
 class LLVoiceChannelGroup : public LLVoiceChannel
 {
 public:
 	LLVoiceChannelGroup(const LLUUID& session_id, const LLString& session_name);
-	virtual ~LLVoiceChannelGroup();
 
 	/*virtual*/ void handleStatusChange(EStatusType status);
 	/*virtual*/ void handleError(EStatusType status);
@@ -132,8 +139,7 @@ class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoice
 {
 public:
 	LLVoiceChannelProximal();
-	virtual ~LLVoiceChannelProximal();
-	
+
 	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
 	/*virtual*/ void handleStatusChange(EStatusType status);
 	/*virtual*/ void handleError(EStatusType status);
@@ -147,7 +153,6 @@ class LLVoiceChannelP2P : public LLVoiceChannelGroup
 {
 public:
 	LLVoiceChannelP2P(const LLUUID& session_id, const LLString& session_name, const LLUUID& other_user_id);
-	virtual ~LLVoiceChannelP2P();
 
 	/*virtual*/ void handleStatusChange(EStatusType status);
 	/*virtual*/ void handleError(EStatusType status);
@@ -156,9 +161,13 @@ class LLVoiceChannelP2P : public LLVoiceChannelGroup
 
 	void setSessionHandle(const LLString& handle);
 
+protected:
+	virtual void setState(EState state);
+
 private:
 	LLString	mSessionHandle;
 	LLUUID		mOtherUserID;
+	BOOL		mReceivedCall;
 };
 
 class LLFloaterIMPanel : public LLFloater
@@ -170,15 +179,11 @@ class LLFloaterIMPanel : public LLFloater
 	// the default. For example, if you open a session though a
 	// calling card, a new session id will be generated, but the
 	// target_id will be the agent referenced by the calling card.
-	LLFloaterIMPanel(const std::string& name,
-					 const LLRect& rect,
-					 const std::string& session_label,
+	LLFloaterIMPanel(const std::string& session_label,
 					 const LLUUID& session_id,
 					 const LLUUID& target_id,
 					 EInstantMessage dialog);
-	LLFloaterIMPanel(const std::string& name,
-					 const LLRect& rect,
-					 const std::string& session_label,
+	LLFloaterIMPanel(const std::string& session_label,
 					 const LLUUID& session_id,
 					 const LLUUID& target_id,
 					 const LLDynamicArray<LLUUID>& ids,
@@ -189,8 +194,8 @@ class LLFloaterIMPanel : public LLFloater
 
 	// Check typing timeout timer.
 	/*virtual*/ void draw();
-
 	/*virtual*/ void onClose(bool app_quitting = FALSE);
+	/*virtual*/ void onVisibilityChange(BOOL new_visibility);
 
 	// add target ids to the session. 
 	// Return TRUE if successful, otherwise FALSE.
@@ -209,14 +214,16 @@ class LLFloaterIMPanel : public LLFloater
 	void selectNone();
 	void setVisible(BOOL b);
 
+	S32 getNumUnreadMessages() { return mNumUnreadMessages; }
+
 	BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
 	BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
 						   BOOL drop, EDragAndDropType cargo_type,
 						   void *cargo_data, EAcceptance *accept,
 						   LLString& tooltip_msg);
 
-	static void		onInputEditorFocusReceived( LLUICtrl* caller, void* userdata );
-	static void		onInputEditorFocusLost(LLUICtrl* caller, void* userdata);
+	static void		onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata );
+	static void		onInputEditorFocusLost(LLFocusableElement* caller, void* userdata);
 	static void		onInputEditorKeystroke(LLLineEditor* caller, void* userdata);
 	static void		onCommitChat(LLUICtrl* caller, void* userdata);
 	static void		onTabClick( void* userdata );
@@ -229,16 +236,17 @@ class LLFloaterIMPanel : public LLFloater
 	static void		onClickSend( void* userdata );
 	static void		onClickToggleActiveSpeakers( void* userdata );
 	static void*	createSpeakersPanel(void* data);
+	static void		onKickSpeaker(void* user_data);
 
 	//callbacks for P2P muting and volume control
-	static void onClickMuteVoice(LLUICtrl* source, void* user_data);
+	static void onClickMuteVoice(void* user_data);
 	static void onVolumeChange(LLUICtrl* source, void* user_data);
 
 	const LLUUID& getSessionID() const { return mSessionUUID; }
 	const LLUUID& getOtherParticipantID() const { return mOtherParticipantUUID; }
-	void updateSpeakersList(LLSD speaker_updates);
-	void setSpeakersListFromMap(LLSD speaker_list);
-	void setSpeakersList(LLSD speaker_list);
+	void updateSpeakersList(const LLSD& speaker_updates);
+	void processSessionUpdate(const LLSD& update);
+	void setSpeakers(const LLSD& speaker_list);
 	LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
 	EInstantMessage getDialogType() const { return mDialog; }
 
@@ -250,6 +258,15 @@ class LLFloaterIMPanel : public LLFloater
 	void processIMTyping(const LLIMInfo* im_info, BOOL typing);
 	static void chatFromLogFile(LLString line, void* userdata);
 
+	//show error statuses to the user
+	void showSessionStartError(const std::string& error_string);
+	void showSessionEventError(
+		const std::string& event_string,
+		const std::string& error_string);
+	void showSessionForceClose(const std::string& reason);
+
+	static void onConfirmForceCloseError(S32 option, void* data);
+
 private:
 	// called by constructors
 	void init(const LLString& session_label);
@@ -289,6 +306,7 @@ class LLFloaterIMPanel : public LLFloater
 	//   911 ==> Gaurdian_Angel_Group_ID ^ gAgent.getID()
 	LLUUID mSessionUUID;
 
+	LLString mSessionLabel;
 	LLVoiceChannel*	mVoiceChannel;
 
 	BOOL mSessionInitialized;
@@ -318,6 +336,8 @@ class LLFloaterIMPanel : public LLFloater
 	// Where does the "Starting session..." line start?
 	S32 mSessionStartMsgPos;
 	
+	S32 mNumUnreadMessages;
+
 	BOOL mSentTypingState;
 
 	BOOL mShowSpeakersOnConnect;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 9c37f1f33329a06e0e340ed600de88a9b0fcf082..f93f5810c5345b89f7a49ce77485cf8c3e07d629 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -46,7 +46,6 @@
 #include "llagent.h"
 #include "llcallingcard.h"
 #include "llchat.h"
-#include "llviewerwindow.h"
 #include "llresmgr.h"
 #include "llfloaterchat.h"
 #include "llfloaterchatterbox.h"
@@ -65,6 +64,7 @@
 #include "llcallingcard.h"
 #include "lltoolbar.h"
 #include "llviewermessage.h"
+#include "llviewerwindow.h"
 #include "llnotify.h"
 #include "llviewerregion.h"
 
@@ -84,11 +84,12 @@ LLIMMgr* gIMMgr = NULL;
 //*FIXME: make these all either UIStrings or Strings
 static LLString sOnlyUserMessage;
 static LLUIString sOfflineMessage;
-
-static std::map<std::string,LLString> sEventStringsMap;
-static std::map<std::string,LLString> sErrorStringsMap;
-static std::map<std::string,LLString> sForceCloseSessionMap;
 static LLUIString sInviteMessage;
+
+std::map<std::string,LLString> LLFloaterIM::sEventStringsMap;
+std::map<std::string,LLString> LLFloaterIM::sErrorStringsMap;
+std::map<std::string,LLString> LLFloaterIM::sForceCloseSessionMap;
+
 //
 // Helper Functions
 //
@@ -160,22 +161,54 @@ BOOL LLFloaterIM::postBuild()
 	sOnlyUserMessage = getFormattedUIString("only_user_message");
 	sOfflineMessage = getUIString("offline_message");
 
-	sErrorStringsMap["generic"] =
-		getFormattedUIString("generic_request_error");
-	sErrorStringsMap["unverified"] =
-		getFormattedUIString("insufficient_perms_error");
-	sErrorStringsMap["no_user_911"] =
-		getFormattedUIString("user_no_help");
+	sInviteMessage = getUIString("invite_message");
 
-	sEventStringsMap["add"] =
-		getFormattedUIString("add_session_event");
-	sEventStringsMap["message"] =
-		getFormattedUIString("message_session_event");
+	if ( sErrorStringsMap.find("generic") == sErrorStringsMap.end() )
+	{
+		sErrorStringsMap["generic"] =
+			getFormattedUIString("generic_request_error");
+	}
 
-	sForceCloseSessionMap["removed"] =
-		getFormattedUIString("removed_from_group");
+	if ( sErrorStringsMap.find("unverified") ==
+		 sErrorStringsMap.end() )
+	{
+		sErrorStringsMap["unverified"] =
+			getFormattedUIString("insufficient_perms_error");
+	}
+
+	if ( sErrorStringsMap.end() ==
+		 sErrorStringsMap.find("does not exist") )
+	{
+		sErrorStringsMap["does not exist"] =
+			getFormattedUIString("session_does_not_exist_error");
+	}
+
+	if ( sEventStringsMap.end() == sEventStringsMap.find("add") )
+	{
+		sEventStringsMap["add"] =
+			getFormattedUIString("add_session_event");
+	}
+
+	if ( sEventStringsMap.end() == sEventStringsMap.find("message") )
+	{
+		sEventStringsMap["message"] =
+			getFormattedUIString("message_session_event");
+	}
+
+	if ( sForceCloseSessionMap.end() ==
+		 sForceCloseSessionMap.find("removed") )
+	{
+		sForceCloseSessionMap["removed"] =
+			getFormattedUIString("removed_from_group");
+	}
+
+	if ( sForceCloseSessionMap.end() ==
+		 sForceCloseSessionMap.find("no ability") )
+	{
+		sForceCloseSessionMap["no ability"] =
+			getFormattedUIString("close_on_no_ability");
+	}
 
-	sInviteMessage = getUIString("invite_message");
 	return TRUE;
 }
 
@@ -205,21 +238,31 @@ class LLIMViewFriendObserver : public LLFriendObserver
 class LLIMMgr::LLIMSessionInvite
 {
 public:
-	LLIMSessionInvite(const LLUUID& session_id, const LLString& session_name, const LLUUID& caller_id,const LLString& caller_name, EInstantMessage type, const LLString& session_handle, const LLString& notify_box) : 
-						mSessionID(session_id),
-						mSessionName(session_name),
-						mCallerID(caller_id),
-						mCallerName(caller_name),
-						mType(type),
-						mSessionHandle(session_handle),
-						mNotifyBox(notify_box)
-						{};
+	LLIMSessionInvite(
+		const LLUUID& session_id,
+		const LLString& session_name,
+		const LLUUID& caller_id,
+		const LLString& caller_name,
+		EInstantMessage type,
+		EInvitationType inv_type,
+		const LLString& session_handle,
+		const LLString& notify_box) : 
+		mSessionID(session_id),
+		mSessionName(session_name),
+		mCallerID(caller_id),
+		mCallerName(caller_name),
+		mType(type),
+		mInvType(inv_type),
+		mSessionHandle(session_handle),
+		mNotifyBox(notify_box)
+	{};
 
 	LLUUID		mSessionID;
 	LLString	mSessionName;
 	LLUUID		mCallerID;
 	LLString	mCallerName;
 	EInstantMessage mType;
+	EInvitationType mInvType;
 	LLString	mSessionHandle;
 	LLString	mNotifyBox;
 };
@@ -309,7 +352,7 @@ LLIMMgr::LLIMMgr() :
 	LLFloaterIM* dummy_floater = new LLFloaterIM();
 	delete dummy_floater;
 
-	mPendingVoiceInvitations = LLSD::emptyMap();
+	mPendingInvitations = LLSD::emptyMap();
 	mPendingAgentListUpdates = LLSD::emptyMap();
 }
 
@@ -413,7 +456,6 @@ void LLIMMgr::addMessage(
 	if ( is_from_system ) // chat came from system
 	{
 		floater->addHistoryLine(
-			other_participant_id,
 			msg,
 			gSavedSettings.getColor4("SystemChatColor"));
 	}
@@ -521,9 +563,10 @@ LLUUID LLIMMgr::addP2PSession(const std::string& name,
 // the session, dialog specifies the type of session. If the session
 // exists, it is brought forward.  Specifying id = NULL results in an
 // im session to everyone. Returns the uuid of the session.
-LLUUID LLIMMgr::addSession(const std::string& name,
-							EInstantMessage dialog,
-							const LLUUID& other_participant_id)
+LLUUID LLIMMgr::addSession(
+	const std::string& name,
+	EInstantMessage dialog,
+	const LLUUID& other_participant_id)
 {
 	LLUUID session_id = computeSessionID(dialog, other_participant_id);
 
@@ -533,15 +576,16 @@ LLUUID LLIMMgr::addSession(const std::string& name,
 		LLDynamicArray<LLUUID> ids;
 		ids.put(other_participant_id);
 
-		floater = createFloater(session_id,
-								other_participant_id,
-								name,
-								ids,
-								dialog,
-								TRUE);
+		floater = createFloater(
+			session_id,
+			other_participant_id,
+			name,
+			ids,
+			dialog,
+			TRUE);
 
 		noteOfflineUsers(floater, ids);
-		LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater);
+		LLFloaterChatterBox::showInstance(session_id);
 	}
 	else
 	{
@@ -554,36 +598,43 @@ LLUUID LLIMMgr::addSession(const std::string& name,
 
 // Adds a session using the given session_id.  If the session already exists 
 // the dialog type is assumed correct. Returns the uuid of the session.
-LLUUID LLIMMgr::addSession(const std::string& name,
-							EInstantMessage dialog,
-							const LLUUID& other_participant_id,
-							const LLDynamicArray<LLUUID>& ids)
+LLUUID LLIMMgr::addSession(
+	const std::string& name,
+	EInstantMessage dialog,
+	const LLUUID& other_participant_id,
+	const LLDynamicArray<LLUUID>& ids)
 {
 	if (0 == ids.getLength())
 	{
 		return LLUUID::null;
 	}
 
-	LLUUID session_id = computeSessionID(dialog,
-										   other_participant_id);
+	LLUUID session_id = computeSessionID(
+		dialog,
+		other_participant_id);
 
 	LLFloaterIMPanel* floater = findFloaterBySession(session_id);
 	if(!floater)
 	{
 		// On creation, use the first element of ids as the
 		// "other_participant_id"
-		floater = createFloater(session_id,
-								other_participant_id,
-								name,
-								ids,
-								dialog,
-								TRUE);
+		floater = createFloater(
+			session_id,
+			other_participant_id,
+			name,
+			ids,
+			dialog,
+			TRUE);
 
 		if ( !floater ) return LLUUID::null;
 
 		noteOfflineUsers(floater, ids);
+		LLFloaterChatterBox::showInstance(session_id);
+	}
+	else
+	{
+		floater->open();
 	}
-	LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater);
 	//mTabContainer->selectTabPanel(panel);
 	floater->setInputFocus(TRUE);
 	return floater->getSessionID();
@@ -599,6 +650,9 @@ void LLIMMgr::removeSession(const LLUUID& session_id)
 		mFloaters.erase(floater->getHandle());
 		LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater);
 		//mTabContainer->removeTabPanel(floater);
+
+		clearPendingInviation(session_id);
+		clearPendingAgentListUpdates(session_id);
 	}
 }
 
@@ -608,9 +662,10 @@ void LLIMMgr::inviteToSession(
 	const LLUUID& caller_id, 
 	const LLString& caller_name,
 	EInstantMessage type,
+	EInvitationType inv_type,
 	const LLString& session_handle)
 {
-	//ignore voice invites from voice-muted residents
+	//ignore invites from muted residents
 	if (gMuteListp->isMuted(caller_id))
 	{
 		return;
@@ -621,17 +676,26 @@ void LLIMMgr::inviteToSession(
 	BOOL ad_hoc_invite = FALSE;
 	if(type == IM_SESSION_P2P_INVITE)
 	{
+		//P2P is different...they only have voice invitations
 		notify_box_type = "VoiceInviteP2P";
 	}
-	else if (gAgent.isInGroup(session_id))
+	else if ( gAgent.isInGroup(session_id) )
 	{
+		//only really old school groups have voice invitations
 		notify_box_type = "VoiceInviteGroup";
 	}
-	else	
+	else if ( inv_type == INVITATION_TYPE_VOICE )
 	{
+		//else it's an ad-hoc
+		//and a voice ad-hoc
 		notify_box_type = "VoiceInviteAdHoc";
 		ad_hoc_invite = TRUE;
 	}
+	else if ( inv_type == INVITATION_TYPE_IMMEDIATE )
+	{
+		notify_box_type = "InviteAdHoc";
+		ad_hoc_invite = TRUE;
+	}
 
 	LLIMSessionInvite* invite = new LLIMSessionInvite(
 		session_id,
@@ -639,6 +703,7 @@ void LLIMMgr::inviteToSession(
 		caller_id,
 		caller_name,
 		type,
+		inv_type,
 		session_handle,
 		notify_box_type);
 	
@@ -666,7 +731,7 @@ void LLIMMgr::inviteToSession(
 		}
 	}
 
-	if ( !mPendingVoiceInvitations.has(session_id.asString()) )
+	if ( !mPendingInvitations.has(session_id.asString()) )
 	{
 		if (caller_name.empty())
 		{
@@ -684,7 +749,7 @@ void LLIMMgr::inviteToSession(
 								 (void*)invite);
 
 		}
-		mPendingVoiceInvitations[session_id.asString()] = LLSD();
+		mPendingInvitations[session_id.asString()] = LLSD();
 	}
 }
 
@@ -699,10 +764,11 @@ void LLIMMgr::onInviteNameLookup(const LLUUID& id, const char* first, const char
 	LLString::format_map_t args;
 	args["[NAME]"] = invite->mCallerName;
 
-	LLNotifyBox::showXml(invite->mNotifyBox,
-						args, 
-						inviteUserResponse, 
-						(void*)invite);
+	LLNotifyBox::showXml(
+		invite->mNotifyBox,
+		args, 
+		inviteUserResponse, 
+		(void*)invite);
 }
 
 class LLViewerChatterBoxInvitationAcceptResponder :
@@ -711,10 +777,10 @@ class LLViewerChatterBoxInvitationAcceptResponder :
 public:
 	LLViewerChatterBoxInvitationAcceptResponder(
 		const LLUUID& session_id,
-		bool is_voice_invitation)
+		LLIMMgr::EInvitationType invitation_type)
 	{
 		mSessionID = session_id;
-		mIsVoiceInvitiation = is_voice_invitation;
+		mInvitiationType = invitation_type;
 	}
 
 	void result(const LLSD& content)
@@ -738,48 +804,67 @@ class LLViewerChatterBoxInvitationAcceptResponder :
 				//but unfortunately, our base that we are receiving here
 				//may not be the most up to date.  It was accurate at
 				//some point in time though.
-				floaterp->setSpeakersList(content["agents"]);
+				floaterp->setSpeakers(content);
 
 				//we now have our base of users in the session
 				//that was accurate at some point, but maybe not now
 				//so now we apply all of the udpates we've received
 				//in case of race conditions
-
-				//reapplying a user entrance will do nothing
-				//reapplying a user leaving will not have the user
-				//in our base.  So it's all good
 				floaterp->updateSpeakersList(
 					gIMMgr->getPendingAgentListUpdates(mSessionID));
 
-				if ( mIsVoiceInvitiation )
+				if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE )
 				{
 					floaterp->requestAutoConnect();
 					LLFloaterIMPanel::onClickStartCall(floaterp);
 					// always open IM window when connecting to voice
 					LLFloaterChatterBox::showInstance(TRUE);
 				}
+				else if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE )
+				{
+					LLFloaterChatterBox::showInstance(TRUE);
+				}
 			}
 
 			gIMMgr->clearPendingAgentListUpdates(mSessionID);
-			if ( mIsVoiceInvitiation )
-			{
-				gIMMgr->clearPendingVoiceInviation(mSessionID);
-			}
+			gIMMgr->clearPendingInviation(mSessionID);
 		}
 	}
 
 	void error(U32 statusNum, const std::string& reason)
 	{
+		
 		//throw something back to the viewer here?
-		if ( gIMMgr && mIsVoiceInvitiation )
+		if ( gIMMgr )
 		{
-			gIMMgr->clearPendingVoiceInviation(mSessionID);
+			gIMMgr->clearPendingAgentListUpdates(mSessionID);
+			gIMMgr->clearPendingInviation(mSessionID);
+
+			LLFloaterIMPanel* floaterp =
+				gIMMgr->findFloaterBySession(mSessionID);
+
+			if (floaterp)
+			{
+				std::string error_string;
+
+				if ( 404 == statusNum )
+				{
+					error_string = "does not exist";
+				}
+				else
+				{
+					error_string = "generic_request_error";
+				}
+
+				floaterp->showSessionStartError(
+					error_string);
+			}
 		}
 	}
 
 private:
 	LLUUID mSessionID;
-	bool mIsVoiceInvitiation;
+	LLIMMgr::EInvitationType mInvitiationType;
 };
 
 //static
@@ -807,10 +892,11 @@ void LLIMMgr::inviteUserResponse(S32 option, void* user_data)
 					im_floater->requestAutoConnect();
 					LLFloaterIMPanel::onClickStartCall(im_floater);
 					// always open IM window when connecting to voice
-					LLFloaterChatterBox::showInstance(TRUE);
+					LLFloaterChatterBox::showInstance(invitep->mSessionID);
 				}
-				
-				gIMMgr->clearPendingVoiceInviation(invitep->mSessionID);
+
+				gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID);
+				gIMMgr->clearPendingInviation(invitep->mSessionID);
 			}
 			else
 			{
@@ -830,34 +916,50 @@ void LLIMMgr::inviteUserResponse(S32 option, void* user_data)
 					data,
 					new LLViewerChatterBoxInvitationAcceptResponder(
 						invitep->mSessionID,
-						true));
+						invitep->mInvType));
 			}
 		}
 		break;
 	case 2: // mute (also implies ignore, so this falls through to the "ignore" case below)
+	{
+		// mute the sender of this invite
+		if (!gMuteListp->isMuted(invitep->mCallerID))
 		{
-			// mute the sender of this invite
-			if (!gMuteListp->isMuted(invitep->mCallerID))
-			{
-				LLMute mute(invitep->mCallerID, invitep->mCallerName, LLMute::AGENT);
-				gMuteListp->add(mute);
-			}
+			LLMute mute(invitep->mCallerID, invitep->mCallerName, LLMute::AGENT);
+			gMuteListp->add(mute);
 		}
+	}
 	/* FALLTHROUGH */
 	
-	case 1: // ignore
+	case 1: // decline
+	{
+		if (invitep->mType == IM_SESSION_P2P_INVITE)
 		{
-			if (invitep->mType == IM_SESSION_P2P_INVITE)
+			if(gVoiceClient)
 			{
-				if(gVoiceClient)
-				{
-					gVoiceClient->declineInvite(invitep->mSessionHandle);
-				}
+				gVoiceClient->declineInvite(invitep->mSessionHandle);
 			}
 		}
-		break;
+		else
+		{
+			std::string url = gAgent.getRegion()->getCapability(
+				"ChatSessionRequest");
+
+			LLSD data;
+			data["method"] = "decline invitation";
+			data["session-id"] = invitep->mSessionID;
+			LLHTTPClient::post(
+				url,
+				data,
+				NULL);				
+		}
 	}
 
+	gIMMgr->clearPendingAgentListUpdates(invitep->mSessionID);
+	gIMMgr->clearPendingInviation(invitep->mSessionID);
+	break;
+	}
+	
 	delete invitep;
 }
 
@@ -869,11 +971,11 @@ void LLIMMgr::setFloaterOpen(BOOL set_open)
 {
 	if (set_open)
 	{
-		LLFloaterChatterBox::showInstance(LLSD());
+		LLFloaterChatterBox::showInstance();
 	}
 	else
 	{
-		LLFloaterChatterBox::hideInstance(LLSD());
+		LLFloaterChatterBox::hideInstance();
 	}
 }
 
@@ -932,11 +1034,11 @@ BOOL LLIMMgr::hasSession(const LLUUID& session_id)
 	return (findFloaterBySession(session_id) != NULL);
 }
 
-void LLIMMgr::clearPendingVoiceInviation(const LLUUID& session_id)
+void LLIMMgr::clearPendingInviation(const LLUUID& session_id)
 {
-	if ( mPendingVoiceInvitations.has(session_id.asString()) )
+	if ( mPendingInvitations.has(session_id.asString()) )
 	{
-		mPendingVoiceInvitations.erase(session_id.asString());
+		mPendingInvitations.erase(session_id.asString());
 	}
 }
 
@@ -958,13 +1060,57 @@ void LLIMMgr::addPendingAgentListUpdates(
 {
 	LLSD::map_const_iterator iter;
 
-	for ( iter = updates.beginMap();
-		  iter != updates.endMap();
-		  iter++)
+	if ( !mPendingAgentListUpdates.has(session_id.asString()) )
 	{
-		//we only want to include the last update for a given agent
-		mPendingAgentListUpdates[session_id.asString()][iter->first] =
-			iter->second;
+		//this is a new agent list update for this session
+		mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap();
+	}
+
+	if (
+		updates.has("agent_updates") &&
+		updates["agent_updates"].isMap() &&
+		updates.has("updates") &&
+		updates["updates"].isMap() )
+	{
+		//new school update
+		LLSD update_types = LLSD::emptyArray();
+		LLSD::array_iterator array_iter;
+
+		update_types.append("agent_updates");
+		update_types.append("updates");
+
+		for (
+			array_iter = update_types.beginArray();
+			array_iter != update_types.endArray();
+			++array_iter)
+		{
+			//we only want to include the last update for a given agent
+			for (
+				iter = updates[array_iter->asString()].beginMap();
+				iter != updates[array_iter->asString()].endMap();
+				++iter)
+			{
+				mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] =
+					iter->second;
+			}
+		}
+	}
+	else if (
+		updates.has("updates") &&
+		updates["updates"].isMap() )
+	{
+		//old school update where the SD contained just mappings
+		//of agent_id -> "LEAVE"/"ENTER"
+
+		//only want to keep last update for each agent
+		for (
+			iter = updates["updates"].beginMap();
+			iter != updates["updates"].endMap();
+			++iter)
+		{
+			mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] =
+				iter->second;
+		}
 	}
 }
 
@@ -995,8 +1141,6 @@ LLFloaterIMPanel* LLIMMgr::createFloater(
 	llinfos << "LLIMMgr::createFloater: from " << other_participant_id 
 			<< " in session " << session_id << llendl;
 	LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
-													 LLRect(),
-													 session_label,
 													 session_id,
 													 other_participant_id,
 													 dialog);
@@ -1022,8 +1166,6 @@ LLFloaterIMPanel* LLIMMgr::createFloater(
 	llinfos << "LLIMMgr::createFloater: from " << other_participant_id 
 			<< " in session " << session_id << llendl;
 	LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
-													 LLRect(),
-													 session_label,
 													 session_id,
 													 other_participant_id,
 													 ids,
@@ -1034,8 +1176,9 @@ LLFloaterIMPanel* LLIMMgr::createFloater(
 	return floater;
 }
 
-void LLIMMgr::noteOfflineUsers(LLFloaterIMPanel* floater,
-								  const LLDynamicArray<LLUUID>& ids)
+void LLIMMgr::noteOfflineUsers(
+	LLFloaterIMPanel* floater,
+	const LLDynamicArray<LLUUID>& ids)
 {
 	S32 count = ids.count();
 	if(count == 0)
@@ -1099,14 +1242,6 @@ LLFloaterChatterBox* LLIMMgr::getFloater()
 	return LLFloaterChatterBox::getInstance(LLSD()); 
 }
 
-void onConfirmForceCloseError(S32 option, void* data)
-{
-	//only 1 option really
-	LLFloaterIMPanel* floater = ((LLFloaterIMPanel*) data);
-
-	if ( floater ) floater->close(FALSE);
-}
-
 class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
 {
 public:
@@ -1141,7 +1276,16 @@ class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
 			LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);
 			if (floaterp)
 			{
-				floaterp->setSpeakersList(body["agents"]);
+				floaterp->setSpeakers(body);
+
+				//apply updates we've possibly received previously
+				floaterp->updateSpeakersList(
+					gIMMgr->getPendingAgentListUpdates(session_id));
+
+				if ( body.has("session_info") )
+				{
+					floaterp->processSessionUpdate(body["session_info"]);
+				}
 
 				//aply updates we've possibly received previously
 				floaterp->updateSpeakersList(
@@ -1155,20 +1299,14 @@ class LLViewerChatterBoxSessionStartReply : public LLHTTPNode
 			//floater
 			LLFloaterIMPanel* floater = 
 				gIMMgr->findFloaterBySession(temp_session_id);
-			if (floater)
-			{
-				LLString::format_map_t args;
-				args["[REASON]"] =
-					sErrorStringsMap[body["error"].asString()];
-				args["[RECIPIENT]"] = floater->getTitle();
-
-				gViewerWindow->alertXml("ChatterBoxSessionStartError",
-										args,
-										onConfirmForceCloseError,
-										floater);
 
+			if ( floater )
+			{
+				floater->showSessionStartError(body["error"].asString());
 			}
 		}
+
+		gIMMgr->clearPendingAgentListUpdates(session_id);
 	}
 };
 
@@ -1200,17 +1338,12 @@ class LLViewerChatterBoxSessionEventReply : public LLHTTPNode
 			//throw an error dialog
 			LLFloaterIMPanel* floater = 
 				gIMMgr->findFloaterBySession(session_id);
+
 			if (floater)
 			{
-				LLString::format_map_t args;
-				args["[REASON]"] = 
-					sErrorStringsMap[body["error"].asString()];
-				args["[EVENT]"] =
-					sEventStringsMap[body["event"].asString()];
-				args["[RECIPIENT]"] = floater->getTitle();
-
-				gViewerWindow->alertXml("ChatterBoxSessionEventError",
-										args);
+				floater->showSessionEventError(
+					body["event"].asString(),
+					body["error"].asString());
 			}
 		}
 	}
@@ -1234,15 +1367,7 @@ class LLViewerForceCloseChatterBoxSession: public LLHTTPNode
 
 		if ( floater )
 		{
-			LLString::format_map_t args;
-
-			args["[NAME]"] = floater->getTitle();
-			args["[REASON]"] = sForceCloseSessionMap[reason];
-
-			gViewerWindow->alertXml("ForceCloseChatterBoxSession",
-									args,
-									onConfirmForceCloseError,
-									floater);
+			floater->showSessionForceClose(reason);
 		}
 	}
 };
@@ -1258,7 +1383,8 @@ class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode
 		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
 		if (floaterp)
 		{
-			floaterp->updateSpeakersList(input["body"]["updates"]);
+			floaterp->updateSpeakersList(
+				input["body"]);
 		}
 		else
 		{
@@ -1267,11 +1393,28 @@ class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode
 			//a start or an acceptance of an invitation.  Race condition.
 			gIMMgr->addPendingAgentListUpdates(
 				input["body"]["session_id"].asUUID(),
-				input["body"]["updates"]);
+				input["body"]);
+		}
+	}
+};
+
+class LLViewerChatterBoxSessionUpdate : public LLHTTPNode
+{
+public:
+	virtual void post(
+		ResponsePtr responder,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
+		if (floaterp)
+		{
+			floaterp->processSessionUpdate(input["body"]["info"]);
 		}
 	}
 };
 
+
 class LLViewerChatterBoxInvitation : public LLHTTPNode
 {
 public:
@@ -1281,6 +1424,8 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode
 		const LLSD& context,
 		const LLSD& input) const
 	{
+		//for backwards compatiblity reasons...we need to still
+		//check for 'text' or 'voice' invitations...bleh
 		if ( input["body"].has("instantmessage") )
 		{
 			LLString capability = input["body"]["capabilities"]["call"].asString();
@@ -1397,8 +1542,8 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode
 					url,
 					data,
 					new LLViewerChatterBoxInvitationAcceptResponder(
-						input["body"]["session_id"],
-						false));
+						input["body"]["session_id"].asUUID(),
+						LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE));
 			}
 		} //end if invitation has instant message
 		else if ( input["body"].has("voice") )
@@ -1419,7 +1564,18 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode
 				input["body"]["session_name"].asString(), 
 				input["body"]["from_id"].asUUID(),
 				input["body"]["from_name"].asString(),
-				IM_SESSION_INVITE);
+				IM_SESSION_INVITE,
+				LLIMMgr::INVITATION_TYPE_VOICE);
+		}
+		else if ( input["body"].has("immediate") )
+		{
+			gIMMgr->inviteToSession(
+				input["body"]["session_id"].asUUID(), 
+				input["body"]["session_name"].asString(), 
+				input["body"]["from_id"].asUUID(),
+				input["body"]["from_name"].asString(),
+				IM_SESSION_INVITE,
+				LLIMMgr::INVITATION_TYPE_IMMEDIATE);
 		}
 	}
 };
@@ -1440,6 +1596,10 @@ LLHTTPRegistration<LLViewerChatterBoxSessionAgentListUpdates>
     gHTTPRegistrationMessageChatterboxsessionagentlistupdates(
 	    "/message/ChatterBoxSessionAgentListUpdates");
 
+LLHTTPRegistration<LLViewerChatterBoxSessionUpdate>
+    gHTTPRegistrationMessageChatterBoxSessionUpdate(
+	    "/message/ChatterBoxSessionUpdate");
+
 LLHTTPRegistration<LLViewerChatterBoxInvitation>
     gHTTPRegistrationMessageChatterBoxInvitation(
 		"/message/ChatterBoxInvitation");
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index f5356ef926434352a87774f2a9b05fff517379c4..11a6905a63cc94cd101f9953168922b3daa50a47 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -45,6 +45,13 @@ class LLFloaterIM;
 class LLIMMgr : public LLSingleton<LLIMMgr>
 {
 public:
+	enum EInvitationType
+	{
+		INVITATION_TYPE_INSTANT_MESSAGE = 0,
+		INVITATION_TYPE_VOICE = 1,
+		INVITATION_TYPE_IMMEDIATE = 2
+	};
+
 	LLIMMgr();
 	virtual ~LLIMMgr();
 
@@ -96,12 +103,14 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
 	// deleted.
 	void removeSession(const LLUUID& session_id);
 
-	void inviteToSession(const LLUUID& session_id, 
-						const LLString& session_name, 
-						const LLUUID& caller, 
-						const LLString& caller_name,
-						EInstantMessage type,
-						const LLString& session_handle = LLString::null);
+	void inviteToSession(
+		const LLUUID& session_id, 
+		const LLString& session_name, 
+		const LLUUID& caller, 
+		const LLString& caller_name,
+		EInstantMessage type,
+		EInvitationType inv_type, 
+		const LLString& session_handle = LLString::null);
 
 	//Updates a given session's session IDs.  Does not open,
 	//create or do anything new.  If the old session doesn't
@@ -147,7 +156,7 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
 
 	static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id);
 
-	void clearPendingVoiceInviation(const LLUUID& session_id);
+	void clearPendingInviation(const LLUUID& session_id);
 
 	LLSD getPendingAgentListUpdates(const LLUUID& session_id);
 	void addPendingAgentListUpdates(
@@ -155,6 +164,9 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
 		const LLSD& updates);
 	void clearPendingAgentListUpdates(const LLUUID& session_id);
 
+	//HACK: need a better way of enumerating existing session, or listening to session create/destroy events
+	const std::set<LLViewHandle>& getIMFloaterHandles() { return mFloaters; }
+
 private:
 	class LLIMSessionInvite;
 
@@ -193,7 +205,7 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
 	// An IM has been received that you haven't seen yet.
 	BOOL mIMReceived;
 
-	LLSD mPendingVoiceInvitations;
+	LLSD mPendingInvitations;
 	LLSD mPendingAgentListUpdates;
 };
 
@@ -203,6 +215,10 @@ class LLFloaterIM : public LLMultiFloater
 public:
 	LLFloaterIM();
 	/*virtual*/ BOOL postBuild();
+
+	static std::map<std::string,LLString> sEventStringsMap;
+	static std::map<std::string,LLString> sErrorStringsMap;
+	static std::map<std::string,LLString> sForceCloseSessionMap;
 };
 
 // Globals
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 9c9b1ad2573d9d10c75dec82fc17d7917fe0c58f..d8841afe22416514e2f5329b8c21495394de5973 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -3165,7 +3165,7 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model
 				std::string(),
 				cb);
 		}
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
+		gFocusMgr.setKeyboardFocus(NULL);
 	}
 	else if ("detach" == action)
 	{
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index ca65b879bc4339bbd155a99ce84421ff930ef01d..7b27a830c44ad5017bf3904f7a714e98c5cd82dc 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -2606,7 +2606,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	//	}
 	//
 	//	// restore keyboard focus
-	//	gFocusMgr.setKeyboardFocus(focus_view, callback);
+	//	gFocusMgr.setKeyboardFocus(focus_view);
 	//}
 }
 
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index 20c4a250033d1c20d3c125ab3fc0dd7647eff776..30106443c003c26ac62798dda534e11291742806 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -607,26 +607,26 @@ void LLJoystickCameraRotate::draw()
 	{
 		LLGLSUIDefault gls_ui;
 
-		gl_draw_image( 0, 0, mImageUnselected );
+		mImageUnselected->draw( 0, 0 );
 
 		if( mInTop )
 		{
-			drawRotatedImage( mImageSelected, 0 );
+			drawRotatedImage( mImageSelected->getImage(), 0 );
 		}
 
 		if( mInRight )
 		{
-			drawRotatedImage( mImageSelected, 1 );
+			drawRotatedImage( mImageSelected->getImage(), 1 );
 		}
 
 		if( mInBottom )
 		{
-			drawRotatedImage( mImageSelected, 2 );
+			drawRotatedImage( mImageSelected->getImage(), 2 );
 		}
 
 		if( mInLeft )
 		{
-			drawRotatedImage( mImageSelected, 3 );
+			drawRotatedImage( mImageSelected->getImage(), 3 );
 		}
 
 		if (sDebugRects)
@@ -801,7 +801,7 @@ void LLJoystickCameraZoom::draw()
 		}
 		else
 		{
-			gl_draw_image( 0, 0, mImageUnselected );
+			mImageUnselected->draw( 0, 0 );
 		}
 
 		if (sDebugRects)
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 4d02af8faecb6c710c40a9c9d77f82ae723d4619..60d39b62bd391737aab35ea0806d05ad49d7ae83 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -52,10 +52,11 @@
 #include <boost/tokenizer.hpp>
 
 #include "llcrc.h"
+#include "lldir.h"
 #include "lldispatcher.h"
+#include "llsdserialize.h"
 #include "llxfermanager.h"
 #include "message.h"
-#include "lldir.h"
 
 #include "llagent.h"
 #include "llfloatermute.h"
@@ -67,6 +68,9 @@
 
 LLMuteList* gMuteListp = NULL;
 
+std::map<LLUUID, F32> LLMuteList::sUserVolumeSettings;
+
+
 // "emptymutelist"
 class LLDispatchEmptyMuteList : public LLDispatchHandler
 {
@@ -168,6 +172,24 @@ LLMuteList::LLMuteList() :
 	msg->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList);
 
 	gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
+
+	// load per-resident voice volume information
+	// conceptually, this is part of the mute list information, although it is only stored locally
+	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
+
+	LLSD settings_llsd;
+	llifstream file;
+	file.open(filename.c_str());
+	if (file.is_open())
+	{
+		LLSDSerialize::fromXML(settings_llsd, file);
+	}
+
+	for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+		 iter != settings_llsd.endMap(); ++iter)
+	{
+		sUserVolumeSettings.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal()));
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -175,6 +197,17 @@ LLMuteList::LLMuteList() :
 //-----------------------------------------------------------------------------
 LLMuteList::~LLMuteList()
 {
+	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
+	LLSD settings_llsd;
+
+	for(user_volume_map_t::iterator iter = sUserVolumeSettings.begin(); iter != sUserVolumeSettings.end(); ++iter)
+	{
+		settings_llsd[iter->first.asString()] = iter->second;
+	}
+
+	llofstream file;
+	file.open(filename.c_str());
+	LLSDSerialize::toPrettyXML(settings_llsd, file);
 }
 
 BOOL LLMuteList::isLinden(const LLString& name) const
@@ -588,6 +621,25 @@ void LLMuteList::cache(const LLUUID& agent_id)
 	}
 }
 
+void LLMuteList::setSavedResidentVolume(const LLUUID& id, F32 volume)
+{
+	// store new value in volume settings file
+	sUserVolumeSettings[id] = volume;
+}
+
+F32 LLMuteList::getSavedResidentVolume(const LLUUID& id)
+{
+	const F32 DEFAULT_VOLUME = 0.5f;
+	
+	user_volume_map_t::iterator found_it = sUserVolumeSettings.find(id);
+	if (found_it != sUserVolumeSettings.end())
+	{
+		return found_it->second;
+	}
+	//FIXME: assumes default, should get this from somewhere
+	return DEFAULT_VOLUME;
+}
+
 
 //-----------------------------------------------------------------------------
 // Static message handlers
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 23e0620ade2f93b53950b07e1eceba047541998d..413a2933b31bd4935e105668d533128eb5b8e1b3 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -112,6 +112,9 @@ class LLMuteList
 	// call this method on logout to save everything.
 	void cache(const LLUUID& agent_id);
 
+	void setSavedResidentVolume(const LLUUID& id, F32 volume);
+	F32 getSavedResidentVolume(const LLUUID& id);
+
 private:
 	BOOL loadFromFile(const LLString& filename);
 	BOOL saveToFile(const LLString& filename);
@@ -155,6 +158,9 @@ class LLMuteList
 	BOOL mIsLoaded;
 
 	friend class LLDispatchEmptyMuteList;
+
+	typedef std::map<LLUUID, F32> user_volume_map_t; 
+	static user_volume_map_t sUserVolumeSettings;
 };
 
 class LLMuteListObserver
diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp
index ba1280550fdb59e78a8d9f454c38696551a0ee79..1ca702b0a77f1c54bc24dbb70d0e0a10df1e6d4e 100644
--- a/indra/newview/llnameeditor.cpp
+++ b/indra/newview/llnameeditor.cpp
@@ -53,7 +53,7 @@ LLNameEditor::LLNameEditor(const std::string& name, const LLRect& rect,
 		S32 max_text_length,
 		void (*commit_callback)(LLUICtrl* caller, void* user_data),
 		void (*keystroke_callback)(LLLineEditor* caller, void* user_data),
-		void (*focus_lost_callback)(LLUICtrl* caller, void* user_data),
+		void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data),
 		void* userdata,
 		LLLinePrevalidateFunc prevalidate_func,
 		LLViewBorder::EBevel border_bevel,
diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h
index 526b76b9c05ba118b7705822b34dc5633e0429ad..9c89454c3330bae44fb00b3a481dc56787a078c6 100644
--- a/indra/newview/llnameeditor.h
+++ b/indra/newview/llnameeditor.h
@@ -53,7 +53,7 @@ class LLNameEditor
 		S32 max_text_length = 254,
 		void (*commit_callback)(LLUICtrl* caller, void* user_data) = NULL,
 		void (*keystroke_callback)(LLLineEditor* caller, void* user_data) = NULL,
-		void (*focus_lost_callback)(LLUICtrl* caller, void* user_data) = NULL,
+		void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data) = NULL,
 		void* userdata = NULL,
 		LLLinePrevalidateFunc prevalidate_func = NULL,
 		LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index adcc141bb1e1a722463755f548d52ed3bbfb19f7..a47721be9d7302cf13ffec6a6d34517f1a248d72 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -224,7 +224,7 @@ LLScrollListItem* LLNameListCtrl::addElement(const LLSD& value, EAddPosition pos
 	LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex);
 	((LLScrollListText*)cell)->setText( fullname );
 
-	updateMaxContentWidth(item);
+	calcMaxContentWidth(item);
 
 	// this column is resizable
 	LLScrollListColumn* columnp = getColumn(mNameColumnIndex);
@@ -277,7 +277,7 @@ void LLNameListCtrl::refresh(const LLUUID& id, const char* first,
 			cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex);
 
 			((LLScrollListText*)cell)->setText( fullname );
-			updateMaxContentWidth(item);
+			calcMaxContentWidth(item);
 		}
 	}
 }
diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp
index 15c993e5525e0163046558a13114576d6803d6cd..e7c313638ba8874569c86524053f63fd24fd7464 100644
--- a/indra/newview/lloverlaybar.cpp
+++ b/indra/newview/lloverlaybar.cpp
@@ -39,6 +39,7 @@
 #include "audioengine.h"
 #include "llagent.h"
 #include "llbutton.h"
+#include "llchatbar.h"
 #include "llfocusmgr.h"
 #include "llimview.h"
 #include "llmediaengine.h"
@@ -71,37 +72,14 @@ extern S32 MENU_BAR_HEIGHT;
 //
 
 
-//static
-void* LLOverlayBar::createMasterRemote(void* userdata)
-{
-	LLOverlayBar *self = (LLOverlayBar*)userdata;	
-	self->mMasterRemote =  new LLMediaRemoteCtrl ( "master_volume",
-												   "volume",
-												   LLRect(),
-												   "panel_master_volume.xml");
-	return self->mMasterRemote;
-}
 
 void* LLOverlayBar::createMediaRemote(void* userdata)
 {
 	LLOverlayBar *self = (LLOverlayBar*)userdata;	
-	self->mMediaRemote =  new LLMediaRemoteCtrl ( "media_remote",
-												  "media",
-												  LLRect(),
-												  "panel_media_remote.xml");
+	self->mMediaRemote =  new LLMediaRemoteCtrl ();
 	return self->mMediaRemote;
 }
 
-void* LLOverlayBar::createMusicRemote(void* userdata)
-{
-	LLOverlayBar *self = (LLOverlayBar*)userdata;
-	self->mMusicRemote =  new LLMediaRemoteCtrl ( "music_remote",
-												  "music",
-												  LLRect(),
-												  "panel_music_remote.xml" );		
-	return self->mMusicRemote;
-}
-
 void* LLOverlayBar::createVoiceRemote(void* userdata)
 {
 	LLOverlayBar *self = (LLOverlayBar*)userdata;	
@@ -109,13 +87,14 @@ void* LLOverlayBar::createVoiceRemote(void* userdata)
 	return self->mVoiceRemote;
 }
 
+void* LLOverlayBar::createChatBar(void* userdata)
+{
+	gChatBar = new LLChatBar();
+	return gChatBar;
+}
 
-
-
-LLOverlayBar::LLOverlayBar(const std::string& name, const LLRect& rect)
-	:	LLPanel(name, rect, FALSE),		// not bordered
-		mMasterRemote(NULL),
-		mMusicRemote(NULL),
+LLOverlayBar::LLOverlayBar()
+	:	LLPanel(),
 		mMediaRemote(NULL),
 		mVoiceRemote(NULL),
 		mMediaState(STOPPED),
@@ -127,25 +106,27 @@ LLOverlayBar::LLOverlayBar(const std::string& name, const LLRect& rect)
 	mBuilt = false;
 
 	LLCallbackMap::map_t factory_map;
-	factory_map["master_volume"] = LLCallbackMap(LLOverlayBar::createMasterRemote, this);
 	factory_map["media_remote"] = LLCallbackMap(LLOverlayBar::createMediaRemote, this);
-	factory_map["music_remote"] = LLCallbackMap(LLOverlayBar::createMusicRemote, this);
 	factory_map["voice_remote"] = LLCallbackMap(LLOverlayBar::createVoiceRemote, this);
+	factory_map["chat_bar"] = LLCallbackMap(LLOverlayBar::createChatBar, this);
 	
 	gUICtrlFactory->buildPanel(this, "panel_overlaybar.xml", &factory_map);
-	
+}
+
+BOOL LLOverlayBar::postBuild()
+{
 	childSetAction("IM Received",onClickIMReceived,this);
 	childSetAction("Set Not Busy",onClickSetNotBusy,this);
 	childSetAction("Release Keys",onClickReleaseKeys,this);
 	childSetAction("Mouselook",onClickMouselook,this);
 	childSetAction("Stand Up",onClickStandUp,this);
+	childSetVisible("chat_bar", gSavedSettings.getBOOL("ChatVisible"));
 
 	mIsFocusRoot = TRUE;
 	mBuilt = true;
 
-	// make overlay bar conform to window size
-	setRect(rect);
 	layoutButtons();
+	return TRUE;
 }
 
 LLOverlayBar::~LLOverlayBar()
@@ -176,146 +157,45 @@ void LLOverlayBar::reshape(S32 width, S32 height, BOOL called_from_parent)
 
 void LLOverlayBar::layoutButtons()
 {
-	S32 width = mRect.getWidth();
-	if (width > 1024) width = 1024;
-
-	S32 count = getChildCount();
-	const S32 PAD = gSavedSettings.getS32("StatusBarPad");
-
-	const S32 num_media_controls = 3;
-	S32 media_remote_width = mMediaRemote ? mMediaRemote->getRect().getWidth() : 0;
-	S32 music_remote_width = mMusicRemote ? mMusicRemote->getRect().getWidth() : 0;
-	S32 voice_remote_width = mVoiceRemote ? mVoiceRemote->getRect().getWidth() : 0;
-	S32 master_remote_width = mMasterRemote ? mMasterRemote->getRect().getWidth() : 0;
-
-	// total reserved width for all media remotes
-	const S32 ENDPAD = 20;
-	S32 remote_total_width = media_remote_width + PAD + music_remote_width + PAD + voice_remote_width + PAD + master_remote_width + ENDPAD;
+	LLView* state_buttons_panel = getChildByName("state_buttons", TRUE);
 
-	// calculate button widths
-	F32 segment_width = (F32)(width - remote_total_width) / (F32)(count - num_media_controls);
-
-	S32 btn_width = lltrunc(segment_width - PAD);
-
-	// Evenly space all views
-	LLRect r;
-	S32 i = 0;
-	for (child_list_const_iter_t child_iter = getChildList()->begin();
-		 child_iter != getChildList()->end(); ++child_iter)
+	if (state_buttons_panel)
 	{
-		LLView *view = *child_iter;
-		r = view->getRect();
-		r.mLeft = (width) - llround(remote_total_width + (i-num_media_controls+1)*segment_width);
-		r.mRight = r.mLeft + btn_width;
-		view->setRect(r);
-		i++;
-	}
+		LLViewQuery query;
+		LLWidgetTypeFilter widget_filter(WIDGET_TYPE_BUTTON);
+		query.addPreFilter(LLVisibleFilter::getInstance());
+		query.addPreFilter(LLEnabledFilter::getInstance());
+		query.addPreFilter(&widget_filter);
 
-	// Fix up remotes to have constant width because they can't shrink
-	S32 right = mRect.getWidth() - remote_total_width - PAD;
-	if (mMediaRemote)
-	{
-		r = mMediaRemote->getRect();
-		r.mLeft = right + PAD;
-		right = r.mLeft + media_remote_width;
-		r.mRight = right;
-		mMediaRemote->setRect(r);
-	}
-	if (mMusicRemote)
-	{
-		r = mMusicRemote->getRect();
-		r.mLeft = right + PAD;
-		right = r.mLeft + music_remote_width;
-		r.mRight = right;
-		mMusicRemote->setRect(r);
-	}
-	if (mVoiceRemote)
-	{
-		r = mVoiceRemote->getRect();
-		r.mLeft = right + PAD;
-		right = r.mLeft + voice_remote_width;
-		r.mRight = right;
-		mVoiceRemote->setRect(r);
-	}
-	if (mMasterRemote)
-	{
-		r = mMasterRemote->getRect();
-		r.mLeft = right + PAD;
-		right = r.mLeft + master_remote_width;
-		r.mRight = right;
-		mMasterRemote->setRect(r);
-	}
-	
-	updateRect();
-}
+		child_list_t button_list = query(state_buttons_panel);
 
-void LLOverlayBar::draw()
-{
-	// retrieve rounded rect image
-	LLUUID image_id;
-	image_id.set(gViewerArt.getString("rounded_square.tga"));
-	LLViewerImage* imagep = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
+		const S32 MAX_BAR_WIDTH = 600;
+		S32 bar_width = llclamp(state_buttons_panel->getRect().getWidth(), 0, MAX_BAR_WIDTH);
 
-	if (imagep)
-	{
-		LLGLSTexture texture_enabled;
-		LLViewerImage::bindTexture(imagep);
+		// calculate button widths
+		const S32 MAX_BUTTON_WIDTH = 150;
+		S32 segment_width = llclamp(lltrunc((F32)(bar_width) / (F32)button_list.size()), 0, MAX_BUTTON_WIDTH);
+		S32 btn_width = segment_width - gSavedSettings.getS32("StatusBarPad");
 
-		const S32 PAD = gSavedSettings.getS32("StatusBarPad");
+		// Evenly space all buttons, starting from left
+		S32 left = 0;
+		S32 bottom = 1;
 
-		// draw rounded rect tabs behind all children
-		LLRect r;
-		// focus highlights
-		LLColor4 color = gColors.getColor("FloaterFocusBorderColor");
-		glColor4fv(color.mV);
-		if(gFocusMgr.childHasKeyboardFocus(gBottomPanel))
-		{
-			for (child_list_const_iter_t child_iter = getChildList()->begin();
-				child_iter != getChildList()->end(); ++child_iter)
-			{
-				LLView *view = *child_iter;
-				if(view->getEnabled() && view->getVisible())
-				{
-					r = view->getRect();
-					gl_segmented_rect_2d_tex(r.mLeft - PAD/3 - 1, 
-											r.mTop + 3, 
-											r.mRight + PAD/3 + 1,
-											r.mBottom, 
-											imagep->getWidth(), 
-											imagep->getHeight(), 
-											16, 
-											ROUNDED_RECT_TOP);
-				}
-			}
-		}
-
-		// main tabs
-		for (child_list_const_iter_t child_iter = getChildList()->begin();
-			child_iter != getChildList()->end(); ++child_iter)
+		for (child_list_reverse_iter_t child_iter = button_list.rbegin();
+			child_iter != button_list.rend(); ++child_iter)
 		{
 			LLView *view = *child_iter;
-			if(view->getEnabled() && view->getVisible())
-			{
-				r = view->getRect();
-				// draw a nice little pseudo-3D outline
-				color = gColors.getColor("DefaultShadowDark");
-				glColor4fv(color.mV);
-				gl_segmented_rect_2d_tex(r.mLeft - PAD/3 + 1, r.mTop + 2, r.mRight + PAD/3, r.mBottom, 
-										 imagep->getWidth(), imagep->getHeight(), 16, ROUNDED_RECT_TOP);
-				color = gColors.getColor("DefaultHighlightLight");
-				glColor4fv(color.mV);
-				gl_segmented_rect_2d_tex(r.mLeft - PAD/3, r.mTop + 2, r.mRight + PAD/3 - 3, r.mBottom, 
-										 imagep->getWidth(), imagep->getHeight(), 16, ROUNDED_RECT_TOP);
-				// here's the main background.  Note that it overhangs on the bottom so as to hide the
-				// focus highlight on the bottom panel, thus producing the illusion that the focus highlight
-				// continues around the tabs
-				color = gColors.getColor("FocusBackgroundColor");
-				glColor4fv(color.mV);
-				gl_segmented_rect_2d_tex(r.mLeft - PAD/3 + 1, r.mTop + 1, r.mRight + PAD/3 - 1, r.mBottom - 1, 
-										 imagep->getWidth(), imagep->getHeight(), 16, ROUNDED_RECT_TOP);
-			}
+			LLRect r = view->getRect();
+			r.setOriginAndSize(left, bottom, btn_width, r.getHeight());
+			view->setRect(r);
+			left += segment_width;
 		}
 	}
+}
+
+void LLOverlayBar::draw()
+{
+	childSetVisible("chat_bar", gSavedSettings.getBOOL("ChatVisible"));
 
 	// draw children on top
 	LLPanel::draw();
@@ -325,79 +205,74 @@ void LLOverlayBar::draw()
 // Per-frame updates of visibility
 void LLOverlayBar::refresh()
 {
+	BOOL buttons_changed = FALSE;
+
 	BOOL im_received = gIMMgr->getIMReceived();
-	childSetVisible("IM Received", im_received);
-	childSetEnabled("IM Received", im_received);
+	LLButton* button = LLUICtrlFactory::getButtonByName(this, "IM Received");
+	if (button && button->getVisible() != im_received)
+	{
+		button->setVisible(im_received);
+		sendChildToFront(button);
+		moveChildToBackOfTabGroup(button);
+		buttons_changed = TRUE;
+	}
 
 	BOOL busy = gAgent.getBusy();
-	childSetVisible("Set Not Busy", busy);
-	childSetEnabled("Set Not Busy", busy);
+	button = LLUICtrlFactory::getButtonByName(this, "Set Not Busy");
+	if (button && button->getVisible() != busy)
+	{
+		button->setVisible(busy);
+		sendChildToFront(button);
+		moveChildToBackOfTabGroup(button);
+		buttons_changed = TRUE;
+	}
 
 	BOOL controls_grabbed = gAgent.anyControlGrabbed();
+	button = LLUICtrlFactory::getButtonByName(this, "Release Keys");
 	
-	childSetVisible("Release Keys", controls_grabbed);
-	childSetEnabled("Release Keys", controls_grabbed);
-
+	if (button && button->getVisible() != controls_grabbed)
+	{
+		button->setVisible(controls_grabbed);
+		sendChildToFront(button);
+		moveChildToBackOfTabGroup(button);
+		buttons_changed = TRUE;
+	}
 
 	BOOL mouselook_grabbed;
 	mouselook_grabbed = gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_DOWN_INDEX)
 						|| gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_UP_INDEX);
+	button = LLUICtrlFactory::getButtonByName(this, "Mouselook");
 
-	
-	childSetVisible("Mouselook", mouselook_grabbed);
-	childSetEnabled("Mouselook", mouselook_grabbed);
+	if (button && button->getVisible() != mouselook_grabbed)
+	{
+		button->setVisible(mouselook_grabbed);
+		sendChildToFront(button);
+		moveChildToBackOfTabGroup(button);
+		buttons_changed = TRUE;
+	}
 
 	BOOL sitting = FALSE;
 	if (gAgent.getAvatarObject())
 	{
 		sitting = gAgent.getAvatarObject()->mIsSitting;
-		childSetVisible("Stand Up", sitting);
-		childSetEnabled("Stand Up", sitting);
-		
 	}
+	button = LLUICtrlFactory::getButtonByName(this, "Stand Up");
 
-	if ( mMusicRemote && gAudiop )
+	if (button && button->getVisible() != sitting)
 	{
-		LLParcel* parcel = gParcelMgr->getAgentParcel();
-		if (!parcel 
-			|| parcel->getMusicURL().empty()
-			|| !gSavedSettings.getBOOL("AudioStreamingMusic"))
-		{
-			mMusicRemote->setVisible(FALSE);
-			mMusicRemote->setEnabled(FALSE);
-		}
-		else
-		{
-			mMusicRemote->setVisible(TRUE);
-			mMusicRemote->setEnabled(TRUE);
-		}
+		button->setVisible(sitting);
+		sendChildToFront(button);
+		moveChildToBackOfTabGroup(button);
+		buttons_changed = TRUE;
 	}
 
-	// if there is a url and a texture and media is enabled and available and media streaming is on... (phew!)
-	if ( mMediaRemote )
-	{
-		if (LLMediaEngine::getInstance () &&
-			LLMediaEngine::getInstance ()->getUrl ().length () && 
-			LLMediaEngine::getInstance ()->getImageUUID ().notNull () &&
-			LLMediaEngine::getInstance ()->isEnabled () &&
-			LLMediaEngine::getInstance ()->isAvailable () &&
-			gSavedSettings.getBOOL ( "AudioStreamingVideo" ) )
-		{
-			// display remote control 
-			mMediaRemote->setVisible ( TRUE );
-			mMediaRemote->setEnabled ( TRUE );
-		}
-		else
-		{
-			mMediaRemote->setVisible ( FALSE );
-			mMediaRemote->setEnabled ( FALSE );
-		}
-	}
-	if (mVoiceRemote)
-	{
-		mVoiceRemote->setVisible(LLVoiceClient::voiceEnabled());
-	}
-	
+	// update "remotes"
+	childSetVisible("voice_remote_container", LLVoiceClient::voiceEnabled());
+	enableMediaButtons();
+
+	moveChildToBackOfTabGroup(mMediaRemote);
+	moveChildToBackOfTabGroup(mVoiceRemote);
+
 	// turn off the whole bar in mouselook
 	if (gAgent.cameraMouselook())
 	{
@@ -407,6 +282,11 @@ void LLOverlayBar::refresh()
 	{
 		setVisible(TRUE);
 	}
+
+	if (buttons_changed)
+	{
+		layoutButtons();
+	}
 }
 
 //-----------------------------------------------------------------------
@@ -462,33 +342,25 @@ void LLOverlayBar::mediaPlay(void*)
 	{
 		return;
 	}
-	gOverlayBar->mMediaState = PLAYING; // desired state
-	LLParcel* parcel = gParcelMgr->getAgentParcel();
-	if (parcel)
-	{
-		LLString path("");
-		LLMediaEngine::getInstance()->convertImageAndLoadUrl( true, false, path );
-	}
-}
-//static
-void LLOverlayBar::mediaPause(void*)
-{
-	if (!gOverlayBar)
+
+	if (gOverlayBar->mMediaState != PLAYING)
 	{
-		return;
+		gOverlayBar->mMediaState = PLAYING; // desired state
+		LLParcel* parcel = gParcelMgr->getAgentParcel();
+		if (parcel)
+		{
+			LLString path("");
+			LLMediaEngine::getInstance()->convertImageAndLoadUrl( true, false, path );
+		}
 	}
-	gOverlayBar->mMediaState = PAUSED; // desired state
-	LLMediaEngine::getInstance()->pause();
-}
-//static
-void LLOverlayBar::mediaStop(void*)
-{
-	if (!gOverlayBar)
+	else
 	{
-		return;
+		gOverlayBar->mMediaState = PAUSED; // desired state
+		LLMediaEngine::getInstance()->pause();
 	}
-	gOverlayBar->mMediaState = STOPPED; // desired state
-	LLMediaEngine::getInstance()->stop();
+
+	//gOverlayBar->mMediaState = STOPPED; // desired state
+	//LLMediaEngine::getInstance()->stop();
 }
 
 //static
@@ -498,116 +370,75 @@ void LLOverlayBar::musicPlay(void*)
 	{
 		return;
 	}
-	gOverlayBar->mMusicState = PLAYING; // desired state
-	if (gAudiop)
+	
+	if (gOverlayBar->mMusicState != PLAYING)
 	{
-		LLParcel* parcel = gParcelMgr->getAgentParcel();
-		if ( parcel )
+		gOverlayBar->mMusicState = PLAYING; // desired state
+		if (gAudiop)
 		{
-			// this doesn't work properly when crossing parcel boundaries - even when the 
-			// stream is stopped, it doesn't return the right thing - commenting out for now.
-// 			if ( gAudiop->isInternetStreamPlaying() == 0 )
+			LLParcel* parcel = gParcelMgr->getAgentParcel();
+			if ( parcel )
 			{
-				gAudiop->startInternetStream(parcel->getMusicURL().c_str());
+				// this doesn't work properly when crossing parcel boundaries - even when the 
+				// stream is stopped, it doesn't return the right thing - commenting out for now.
+	// 			if ( gAudiop->isInternetStreamPlaying() == 0 )
+				{
+					gAudiop->startInternetStream(parcel->getMusicURL().c_str());
+				}
 			}
 		}
 	}
-}
-//static
-void LLOverlayBar::musicPause(void*)
-{
-	if (!gOverlayBar)
-	{
-		return;
-	}
-	gOverlayBar->mMusicState = PAUSED; // desired state
-	if (gAudiop)
-	{
-		gAudiop->pauseInternetStream(1);
-	}
-}
-//static
-void LLOverlayBar::musicStop(void*)
-{
-	if (!gOverlayBar)
-	{
-		return;
-	}
-	gOverlayBar->mMusicState = STOPPED; // desired state
-	if (gAudiop)
+	//else
+	//{
+	//	gOverlayBar->mMusicState = PAUSED; // desired state
+	//	if (gAudiop)
+	//	{
+	//		gAudiop->pauseInternetStream(1);
+	//	}
+	//}
+	else
 	{
-		gAudiop->stopInternetStream();
+		gOverlayBar->mMusicState = STOPPED; // desired state
+		if (gAudiop)
+		{
+			gAudiop->stopInternetStream();
+		}
 	}
 }
 
-//static
-void LLOverlayBar::enableMusicButtons(LLPanel* panel)
-{	
-	BOOL play_enabled = FALSE;
-	BOOL play_visible = TRUE;
-	BOOL pause_visible = FALSE;
-	BOOL stop_enabled = FALSE;
-	if ( gAudiop && gOverlayBar && gSavedSettings.getBOOL("AudioStreamingMusic"))
+void LLOverlayBar::enableMediaButtons()
+{
+	if (mMediaRemote)
 	{
-		play_enabled = TRUE;
-		S32 is_playing = gAudiop->isInternetStreamPlaying();
-		if (is_playing == 1)
+		// Music
+		LLParcel* parcel = gParcelMgr->getAgentParcel();
+		if (parcel 
+			&& gAudiop
+			&& !parcel->getMusicURL().empty()
+			&& gSavedSettings.getBOOL("AudioStreamingMusic"))
 		{
-			play_visible = FALSE;
-			pause_visible = TRUE;
-			stop_enabled = TRUE;
+			mMediaRemote->childSetEnabled("music_play", TRUE);
 		}
-		else if (is_playing == 2)
+		else
 		{
-			play_visible = TRUE;
-			pause_visible = FALSE;
-			stop_enabled = TRUE;
+			mMediaRemote->childSetEnabled("music_play", FALSE);
 		}
-	}
-	panel->childSetEnabled("music_play", play_enabled);
-	panel->childSetEnabled("music_pause", play_enabled);
-	panel->childSetVisible("music_play", play_visible);
-	panel->childSetVisible("music_pause", pause_visible);
-	panel->childSetEnabled("music_stop", stop_enabled);
-}
 
-//static
-void LLOverlayBar::enableMediaButtons(LLPanel* panel)
-{
-	// Media
-	BOOL play_enabled = FALSE;
-	BOOL play_visible = TRUE;
-	BOOL pause_visible = FALSE;
-	BOOL stop_enabled = FALSE;
-
-	if ( LLMediaEngine::getInstance() && gOverlayBar && gSavedSettings.getBOOL("AudioStreamingVideo") )
-	{
-		play_enabled = TRUE;
-		if (LLMediaEngine::getInstance()->getMediaRenderer())
+		// Media
+		// if there is a url and a texture and media is enabled and available and media streaming is on... (phew!)
+		if (LLMediaEngine::getInstance() 
+			&& LLMediaEngine::getInstance()->getUrl ().length () 
+			&& LLMediaEngine::getInstance()->getImageUUID ().notNull () 
+			&& LLMediaEngine::getInstance()->isEnabled () 
+			&& LLMediaEngine::getInstance()->isAvailable () 
+			&& gSavedSettings.getBOOL ( "AudioStreamingVideo" ) )
 		{
-			if ( LLMediaEngine::getInstance()->getMediaRenderer()->isPlaying() ||
-				 LLMediaEngine::getInstance()->getMediaRenderer()->isLooping() )
-			{
-				play_visible = FALSE;
-				pause_visible = TRUE;
-				stop_enabled = TRUE;
-			}
-			else if ( LLMediaEngine::getInstance()->getMediaRenderer()->isPaused() )
-			{
-				play_visible = TRUE;
-				pause_visible = FALSE;
-				stop_enabled = TRUE;
-			}
+			mMediaRemote->childSetEnabled("media_play", TRUE);
+		}
+		else
+		{
+			mMediaRemote->childSetEnabled("media_play", FALSE);	
 		}
 	}
-	panel->childSetEnabled("media_play", play_enabled);
-	panel->childSetEnabled("media_pause", play_enabled);
-	panel->childSetVisible("media_play", play_visible);
-	panel->childSetVisible("media_pause", pause_visible);
-	panel->childSetEnabled("media_stop", stop_enabled);
 }
 
-void LLOverlayBar::toggleAudioVolumeFloater(void* user_data)
-{
-	LLFloaterAudioVolume::toggleInstance(LLSD());
-}
diff --git a/indra/newview/lloverlaybar.h b/indra/newview/lloverlaybar.h
index 229346340ade5d64dcc0953b0fc42fe3d394ef04..18ff07e71b16f4129d36e6b2b57b52e17a8371db 100644
--- a/indra/newview/lloverlaybar.h
+++ b/indra/newview/lloverlaybar.h
@@ -54,7 +54,7 @@ class LLOverlayBar
 :	public LLPanel
 {
 public:
-	LLOverlayBar(const std::string& name, const LLRect& rect );
+	LLOverlayBar();
 	~LLOverlayBar();
 
 	virtual EWidgetType getWidgetType() const;
@@ -63,6 +63,7 @@ class LLOverlayBar
 	/*virtual*/ void refresh();
 	/*virtual*/ void draw();
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
+	/*virtual*/ BOOL postBuild();
 
 	void layoutButtons();
 
@@ -79,27 +80,16 @@ class LLOverlayBar
 
 	//static media helper functions
 	static void mediaPlay(void*);
-	static void mediaPause(void*);
-	static void mediaStop(void*);
-	
 	static void musicPlay(void*);
-	static void musicPause(void*);
-	static void musicStop(void*);
 
-	static void toggleAudioVolumeFloater(void*);
-	
-	static void enableMediaButtons(LLPanel* panel);
-	static void enableMusicButtons(LLPanel* panel);
-	
 protected:	
-	static void* createMasterRemote(void* userdata);
-	static void* createMusicRemote(void* userdata);
 	static void* createMediaRemote(void* userdata);
 	static void* createVoiceRemote(void* userdata);
+	static void* createChatBar(void* userdata);
+
+	void enableMediaButtons();
 
 protected:
-	LLMediaRemoteCtrl*	mMasterRemote;
-	LLMediaRemoteCtrl*	mMusicRemote;
 	LLMediaRemoteCtrl*	mMediaRemote;
 	LLVoiceRemoteCtrl*	mVoiceRemote;
 	bool mBuilt;	// dialog constructed yet?
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index c090fd974978bc3c35cc80190d1d792615c8cbea..46af3ec74f1d6a5e911e3d9856e903e246b8646d 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -1638,7 +1638,7 @@ void LLPanelAvatar::onClickMute(void *userdata)
 	if (name_edit)
 	{
 		std::string agent_name = name_edit->getText();
-		gFloaterMute->show();
+		LLFloaterMute::showInstance();
 		
 		if (gMuteListp->isMuted(agent_id))
 		{
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 7163a71bc3e392c6041dec9c5480e4dcf02141bc..7263b11d96a448ebd9a96cf4fed1fefa8bef43b4 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -189,14 +189,14 @@ BOOL LLPanelClassified::postBuild()
     mNameEditor = LLViewerUICtrlFactory::getLineEditorByName(this, "given_name_editor");
 	mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN);
 	mNameEditor->setCommitOnFocusLost(TRUE);
-	mNameEditor->setFocusReceivedCallback(onFocusReceived);
+	mNameEditor->setFocusReceivedCallback(onFocusReceived, this);
 	mNameEditor->setCommitCallback(onCommitAny);
 	mNameEditor->setCallbackUserData(this);
 	mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII );
 
     mDescEditor = LLUICtrlFactory::getTextEditorByName(this, "desc_editor");
 	mDescEditor->setCommitOnFocusLost(TRUE);
-	mDescEditor->setFocusReceivedCallback(onFocusReceived);
+	mDescEditor->setFocusReceivedCallback(onFocusReceived, this);
 	mDescEditor->setCommitCallback(onCommitAny);
 	mDescEditor->setCallbackUserData(this);
 	mDescEditor->setTabToNextField(TRUE);
@@ -929,10 +929,10 @@ void LLPanelClassified::onCommitAny(LLUICtrl* ctrl, void* data)
 }
 
 // static
-void LLPanelClassified::onFocusReceived(LLUICtrl* ctrl, void* data)
+void LLPanelClassified::onFocusReceived(LLFocusableElement* ctrl, void* data)
 {
 	// allow the data to be saved
-	onCommitAny(ctrl, data);
+	onCommitAny((LLUICtrl*)ctrl, data);
 }
 
 
diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h
index a2bb29b2242ac5904f8b55119d49b485e08d0885..8884d1a25ef08aa287de9d9b07df1c7acb221935 100644
--- a/indra/newview/llpanelclassified.h
+++ b/indra/newview/llpanelclassified.h
@@ -111,7 +111,7 @@ class LLPanelClassified : public LLPanel
 	static void onClickProfile(void* data);
     static void onClickSet(void* data);
 
-	static void onFocusReceived(LLUICtrl* ctrl, void* data);
+	static void onFocusReceived(LLFocusableElement* ctrl, void* data);
 	static void onCommitAny(LLUICtrl* ctrl, void* data);
 
 	void sendClassifiedClickMessage(const char* type);
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 8dbe72fdfe3ff644e905097817f0219fe5e555c0..8ce2ae5d9cd61efcd359beb28fdd6ddd4cfb8461 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -870,7 +870,7 @@ void LLPanelFace::onClickApply(void* userdata)
 {
 	LLPanelFace* self = (LLPanelFace*) userdata;
 	
-	gFocusMgr.setKeyboardFocus( NULL, NULL );
+	gFocusMgr.setKeyboardFocus( NULL );
 
 	//F32 repeats_per_meter = self->mCtrlRepeatsPerMeter->get();
 	F32 repeats_per_meter = (F32)self->childGetValue( "rptctrl" ).asReal();//self->mCtrlRepeatsPerMeter->get();
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 3ad65b5e687ce8c631a1621fdf1736079bc15a18..31688256f588a6fc83a090fb3ef549c9d663efc2 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -114,8 +114,8 @@ BOOL LLPanelGroupGeneral::postBuild()
 	if(mEditCharter)
 	{
 		mEditCharter->setCommitCallback(onCommitAny);
-		mEditCharter->setFocusReceivedCallback(onCommitAny);
-		mEditCharter->setFocusChangedCallback(onCommitAny);
+		mEditCharter->setFocusReceivedCallback(onFocusEdit, this);
+		mEditCharter->setFocusChangedCallback(onFocusEdit, this);
 		mEditCharter->setCallbackUserData(this);
 	}
 
@@ -258,6 +258,14 @@ BOOL LLPanelGroupGeneral::postBuild()
 	return LLPanelGroupTab::postBuild();
 }
 
+// static
+void LLPanelGroupGeneral::onFocusEdit(LLFocusableElement* ctrl, void* data)
+{
+	LLPanelGroupGeneral* self = (LLPanelGroupGeneral*)data;
+	self->mChanged = TRUE;
+	self->notifyObservers();
+}
+
 // static
 void LLPanelGroupGeneral::onCommitAny(LLUICtrl* ctrl, void* data)
 {
diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h
index e7a27b6c0beea14f97862dd29a312644d7080d83..b17a66d0a3bd1e12c4f982d1d70fc207e94354c2 100644
--- a/indra/newview/llpanelgroupgeneral.h
+++ b/indra/newview/llpanelgroupgeneral.h
@@ -66,6 +66,7 @@ class LLPanelGroupGeneral : public LLPanelGroupTab
 	virtual void draw();
 
 private:
+	static void onFocusEdit(LLFocusableElement* ctrl, void* data);
 	static void onCommitAny(LLUICtrl* ctrl, void* data);
 	static void onCommitUserOnly(LLUICtrl* ctrl, void* data);
 	static void onCommitTitle(LLUICtrl* ctrl, void* data);
diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp
index 01529907981aed55793675595560ef974080f448..dbe24d40e030839c638b3d4a2c1fa4ec9c9fb230 100644
--- a/indra/newview/llpanelgrouplandmoney.cpp
+++ b/indra/newview/llpanelgrouplandmoney.cpp
@@ -238,7 +238,7 @@ void LLPanelGroupLandMoney::impl::onMapButton()
 
 	F32 global_x = 0.f;
 	F32 global_y = 0.f;
-	sscanf(cellp->getText().c_str(), "%f %f", &global_x, &global_y);
+	sscanf(cellp->getValue().asString().c_str(), "%f %f", &global_x, &global_y);
 
 	// Hack: Use the agent's z-height
 	F64 global_z = gAgent.getPositionGlobal().mdV[VZ];
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index ce824cbb6d0d269a0e36c5582d6dd67bca7deef2..a67692afa6b7eea82a56206f44ea8f892943587f 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -790,7 +790,6 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
 			{
 				row["columns"][column_index]["column"] = "checkbox";
 				row["columns"][column_index]["type"] = "checkbox";
-				row["columns"][column_index]["value"] = (*ra_it)->mName;
 				check_box_index = column_index;
 				++column_index;
 			}
@@ -1058,7 +1057,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
 					if (mi == gdatap->mMembers.end()) continue;
 					LLGroupMemberData* member_data = (*mi).second;
 					// Is the member an owner?
-					if ( member_data->isInRole(gdatap->mOwnerRole) )
+					if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
 					{
 						// Can't remove other owners.
 						cb_enable = FALSE;
@@ -1870,7 +1869,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root)
 	mRoleDescription->setCommitOnFocusLost(TRUE);
 	mRoleDescription->setCallbackUserData(this);
 	mRoleDescription->setCommitCallback(onDescriptionCommit);
-	mRoleDescription->setFocusReceivedCallback(onDescriptionCommit);
+	mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this);
 
 	setFooterEnabled(FALSE);
 
@@ -2328,6 +2327,16 @@ void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_dat
 	self->notifyObservers();
 }
 
+// static 
+void LLPanelGroupRolesSubTab::onDescriptionFocus(LLFocusableElement* ctrl, void* user_data)
+{
+	LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
+	if (!self) return;
+
+	self->mHasRoleChange = TRUE;
+	self->notifyObservers();
+}
+
 // static 
 void LLPanelGroupRolesSubTab::onDescriptionCommit(LLUICtrl* ctrl, void* user_data)
 {
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index b0b635eb576d2dce941139695bc90b091b4832a7..13d64d4edb305b0e68dc3c7f4ee7cdbd9593d39b 100644
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -256,6 +256,7 @@ class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab
 	static void onPropertiesKey(LLLineEditor*, void*);
 
 	static void onDescriptionCommit(LLUICtrl*, void*);
+	static void onDescriptionFocus(LLFocusableElement*, void*);
 
 	static void onMemberVisibilityChange(LLUICtrl*, void*);
 	void handleMemberVisibilityChange(bool value);
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index bc297354f72716a8dc1c9cbb1ae1660c27f7f4fb..74936dce0c51085f2fa4a054e048d00241c9c834 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -496,7 +496,7 @@ void LLPanelLogin::show(const LLRect &rect,
 						void (*callback)(S32 option, void* user_data),
 						void* callback_data)
 {
-	new LLPanelLogin(rect, show_server, callback, callback_data);
+	new LLPanelLogin(rect, show_server, callback, callback_data); 
 
 	LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(sInstance, "login_html");
 	
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index c3d949d3df4327bb66cfd8bc121570d6d6739e1b..2463e62d7f81ce859d00069b774918bf12c4eb88 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -350,7 +350,7 @@ void LLPanelObject::getState( )
 		//forfeit focus
 		if (gFocusMgr.childHasKeyboardFocus(this))
 		{
-			gFocusMgr.setKeyboardFocus(NULL, NULL);
+			gFocusMgr.setKeyboardFocus(NULL);
 		}
 
 		// Disable all text input fields
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index c288c6aaedd501e410d258bc4a20ced05de4913e..e7b5e79377f86c8a150076656fc3f9fe00a7c99d 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -171,7 +171,7 @@ void LLPanelVolume::getState( )
 		//forfeit focus
 		if (gFocusMgr.childHasKeyboardFocus(this))
 		{
-			gFocusMgr.setKeyboardFocus(NULL, NULL);
+			gFocusMgr.setKeyboardFocus(NULL);
 		}
 
 		// Disable all text input fields
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 9fa364a339d4b7f85c7f45f16c8f9cbd7708ec93..61bda9dfc005df6c78828bf3c362707e233d52f3 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -1607,7 +1607,7 @@ void LLPreviewGesture::onClickAdd(void* data)
 	if (!library_item) return;
 
 	const LLScrollListCell* library_cell = library_item->getColumn(0);
-	const std::string& library_text = library_cell->getText();
+	const std::string& library_text = library_cell->getValue().asString();
 
 	self->addStep(library_text);
 
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 6c377009f275dfd6037658cb97ef765f21de712d..06286927d4dd29ae9461d79e8378a4a80c2f606d 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -960,7 +960,7 @@ void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data)
 		S32 row = 0;
 		S32 column = 0;
 		const LLScrollListCell* cell = item->getColumn(0);
-		LLString line(cell->getText());
+		LLString line(cell->getValue().asString());
 		line.erase(0, 1);
 		LLString::replaceChar(line, ',',' ');
 		LLString::replaceChar(line, ')',' ');
diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp
index fae04871be29fd623e2d3c59d98acf10f4cb8733..b92a6d58c8c489198f8f6cc96d0db8c83517c0c8 100644
--- a/indra/newview/llpreviewsound.cpp
+++ b/indra/newview/llpreviewsound.cpp
@@ -106,7 +106,7 @@ void LLPreviewSound::auditionSound( void *userdata )
 	if(item && gAudiop)
 	{
 		LLVector3d lpos_global = gAgent.getPositionGlobal();
-		F32 volume = SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX");
+		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX");
 		gAudiop->triggerSound(item->getAssetUUID(), gAgent.getID(), volume, lpos_global);
 	}
 }
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index f12f5763ef8f45fded9595f2b092e08fa5813abe..b0b9fd33d150b5472aa724a5d65feafe5cbf5983 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2304,7 +2304,7 @@ BOOL idle_startup()
 		audio_update_volume();
 
 		// reset keyboard focus to sane state of pointing at world
-		gFocusMgr.setKeyboardFocus(NULL, NULL);
+		gFocusMgr.setKeyboardFocus(NULL);
 
 #if 0 // sjb: enable for auto-enabling timer display 
 		gDebugView->mFastTimerView->setVisible(TRUE);
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 4d49d33184a86f15e22a665a47a335686a226f66..8c4fc833dbe07472d19b0feab793ea1165e54565 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -100,7 +100,6 @@ const LLColor4 SIM_WARN_COLOR(1.f, 1.f, 0.f, 1.f);
 const LLColor4 SIM_FULL_COLOR(1.f, 0.f, 0.f, 1.f);
 const F32 ICON_TIMER_EXPIRY		= 3.f; // How long the balance and health icons should flash after a change.
 const F32 ICON_FLASH_FREQUENCY	= 2.f;
-const S32 GRAPHIC_FUDGE = 4;
 const S32 TEXT_HEIGHT = 18;
 
 static void onClickParcelInfo(void*);
@@ -153,13 +152,13 @@ LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect)
 	
 	childSetAction("scriptout", onClickScriptDebug, this);
 	childSetAction("health", onClickHealth, this);
-	childSetAction("fly", onClickFly, this);
+	childSetAction("no_fly", onClickFly, this);
 	childSetAction("buyland", onClickBuyLand, this );
 	childSetAction("buycurrency", onClickBuyCurrency, this );
-	childSetAction("build", onClickBuild, this );
-	childSetAction("scripts", onClickScripts, this );
+	childSetAction("no_build", onClickBuild, this );
+	childSetAction("no_scripts", onClickScripts, this );
 	childSetAction("restrictpush", onClickPush, this );
-	childSetAction("status_voice", onClickVoice, this );
+	childSetAction("status_no_voice", onClickVoice, this );
 
 	childSetCommitCallback("search_editor", onCommitSearch, this);
 	childSetAction("search_btn", onClickSearch, this);
@@ -304,7 +303,7 @@ void LLStatusBar::refresh()
 
 		// Health
 		childGetRect( "health", buttonRect );
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
+		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
 		childSetRect("health", r);
 		x += buttonRect.getWidth();
 
@@ -324,27 +323,32 @@ void LLStatusBar::refresh()
 		(parcel && !parcel->getAllowFly()) )
 	{
 		// No Fly Zone
-		childGetRect( "fly", buttonRect );
-		childSetVisible( "fly", true );
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
-		childSetRect( "fly", r );
+		childGetRect( "no_fly", buttonRect );
+		childSetVisible( "no_fly", true );
+		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
+		childSetRect( "no_fly", r );
 		x += buttonRect.getWidth();
 	}
 	else
 	{
-		childSetVisible("fly", false);
+		// Fly Zone
+		childSetVisible("no_fly", false);
 	}
 
 	BOOL no_build = parcel && !parcel->getAllowModify();
-	childSetVisible("build", no_build);
 	if (no_build)
 	{
-		childGetRect( "build", buttonRect );
+		childSetVisible("no_build", TRUE);
+		childGetRect( "no_build", buttonRect );
 		// No Build Zone
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
-		childSetRect( "build", r );
+		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
+		childSetRect( "no_build", r );
 		x += buttonRect.getWidth();
 	}
+	else
+	{
+		childSetVisible("no_build", FALSE);
+	}
 
 	BOOL no_scripts = FALSE;
 	if((region
@@ -354,35 +358,56 @@ void LLStatusBar::refresh()
 	{
 		no_scripts = TRUE;
 	}
-	childSetVisible("scripts", no_scripts);
 	if (no_scripts)
 	{
 		// No scripts
-		childGetRect( "scripts", buttonRect );
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
-		childSetRect( "scripts", r );
+		childSetVisible("no_scripts", TRUE);
+		childGetRect( "no_scripts", buttonRect );
+		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
+		childSetRect( "no_scripts", r );
 		x += buttonRect.getWidth();
 	}
+	else
+	{
+		// Yes scripts
+		childSetVisible("no_scripts", FALSE);
+	}
 
 	BOOL no_region_push = (region && region->getRestrictPushObject());
 	BOOL no_push = no_region_push || (parcel && parcel->getRestrictPushObject());
-	childSetVisible("restrictpush", no_push);
 	if (no_push)
 	{
+		childSetVisible("restrictpush", TRUE);
 		childGetRect( "restrictpush", buttonRect );
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
+		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
 		childSetRect( "restrictpush", r );
 		x += buttonRect.getWidth();
 	}
+	else
+	{
+		childSetVisible("restrictpush", FALSE);
+	}
 
+	BOOL voice_enabled = gVoiceClient->voiceEnabled();
 	BOOL have_voice = parcel && parcel->getVoiceEnabled(); 
-	childSetVisible("status_voice", have_voice);
-	if (have_voice)
+	if (!voice_enabled)
 	{
-		childGetRect( "status_voice", buttonRect );
-		r.setOriginAndSize( x, y-GRAPHIC_FUDGE, buttonRect.getWidth(), buttonRect.getHeight());
-		childSetRect( "status_voice", r );
-		x += buttonRect.getWidth();
+		childSetVisible("status_no_voice", FALSE);
+	}
+	else
+	{
+		if (have_voice)
+		{
+			childSetVisible("status_no_voice", FALSE);
+		}
+		else if (!have_voice)
+		{
+			childSetVisible("status_no_voice", TRUE);
+			childGetRect( "status_no_voice", buttonRect );
+			r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
+			childSetRect( "status_no_voice", r );
+			x += buttonRect.getWidth();
+		}
 	}
 
 	BOOL canBuyLand = parcel
@@ -512,7 +537,7 @@ void LLStatusBar::refresh()
 	mTextParcelName->setText(location_name);
 
 	// Adjust region name and parcel name
-	x += 4;
+	x += 8;
 
 	const S32 PARCEL_RIGHT =  llmin(mTextTime->getRect().mLeft, mTextParcelName->getTextPixelWidth() + x + 5);
 	r.set(x+4, mRect.getHeight() - 2, PARCEL_RIGHT, 0);
@@ -672,8 +697,7 @@ static void onClickPush(void* )
 
 static void onClickVoice(void* )
 {
-	LLNotifyBox::showXml("VoiceAvailablity");
-	//LLFirstUse::useVoice();
+	LLNotifyBox::showXml("NoVoice");
 }
 
 static void onClickBuild(void*)
@@ -708,7 +732,7 @@ static void onClickBuyLand(void*)
 void LLStatusBar::setupDate()
 {
 	// fill the day array with what's in the xui
-	LLString day_list = childGetText("StatBarDaysOfWeek");
+	LLString day_list = getFormattedUIString("StatBarDaysOfWeek");
 	size_t length = day_list.size();
 	
 	// quick input check
@@ -732,7 +756,7 @@ void LLStatusBar::setupDate()
 	}
 	
 	// fill the day array with what's in the xui	
-	LLString month_list = childGetText( "StatBarMonthsOfYear" );
+	LLString month_list = getFormattedUIString( "StatBarMonthsOfYear" );
 	length = month_list.size();
 	
 	// quick input check
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 06a4ea097fb554ba5f6b8496c82d016050af0f58..465a40c1efecfed628d8db65d7ae79873ecd4c6c 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -373,7 +373,6 @@ class LLGLTexMemBar : public LLView
 	{
 		S32 line_height = (S32)(LLFontGL::sMonospace->getLineHeight() + .5f);
 		setRect(LLRect(0,0,100,line_height * 4));
-		updateRect();
 	}
 
 	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_TEX_MEM_BAR; };
diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp
index e7a5445ef631d12a918c9d62f8c62291ce6b5bb8..c80edd0eab0b19bb7e927fe7fae8b3a972b9cc33 100644
--- a/indra/newview/lltoolbar.cpp
+++ b/indra/newview/lltoolbar.cpp
@@ -60,6 +60,11 @@
 #include "llvieweruictrlfactory.h"
 #include "llviewerwindow.h"
 #include "lltoolgrab.h"
+#include "llcombobox.h"
+#include "llfloaterchat.h"
+#include "llfloatermute.h"
+#include "llimpanel.h"
+#include "llscrolllistctrl.h"
 
 #if LL_DARWIN
 
@@ -100,24 +105,20 @@ F32	LLToolBar::sInventoryAutoOpenTime = 1.f;
 // Functions
 //
 
-LLToolBar::LLToolBar(const std::string& name, const LLRect& r)
-:	LLPanel(name, r, BORDER_NO)
+LLToolBar::LLToolBar()
+:	LLPanel()
 #if LL_DARWIN
 	, mResizeHandle(NULL)
 #endif // LL_DARWIN
 {
 	setIsChrome(TRUE);
-	setFollows(	FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM );
-
-	gUICtrlFactory->buildPanel(this, "panel_toolbar.xml");
-	mIsFocusRoot = TRUE;
-
+	setFocusRoot(TRUE);
 }
 
 
 BOOL LLToolBar::postBuild()
 {
-	childSetAction("communicate_btn", onClickCommunicate, this);
+	childSetCommitCallback("communicate_btn", onClickCommunicate, this);
 	childSetControlName("communicate_btn", "ShowCommunicate");
 
 	childSetAction("chat_btn", onClickChat, this);
@@ -270,29 +271,47 @@ void LLToolBar::layoutButtons()
 	}
 #endif // LL_DARWIN
 
+	LLButton* chat_button = LLUICtrlFactory::getButtonByName(this, "chat_btn");
+	if (chat_button)
+	{
+		width -= chat_button->getRect().getWidth() + pad;
+	}
+
 	// We actually want to extend "pad" pixels off the right edge of the    
 	// screen, such that the rightmost button is aligned.                   
-	F32 segment_width = (F32)(width + pad) / (F32)count;                    
-	S32 btn_width = lltrunc(segment_width - pad);                           
+	S32 segment_width = llround((F32)(width) / ((F32)count - 1.f));
+	S32 btn_width = segment_width - pad;
 	
 	// Evenly space all views
 	S32 height = -1;
 	S32 i = count - 1;
-	for (child_list_const_iter_t child_iter = getChildList()->begin();
-		 child_iter != getChildList()->end(); ++child_iter)
+	S32 x = pad;
+	for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin();
+		 child_iter != getChildList()->rend(); ++child_iter)
 	{
 		LLView *btn_view = *child_iter;
-		if(btn_view->getWidgetType() == WIDGET_TYPE_BUTTON)
+		if(btn_view->getWidgetType() == WIDGET_TYPE_BUTTON || btn_view->getWidgetType() == WIDGET_TYPE_FLYOUT_BUTTON)
 		{
 			if (height < 0)
 			{
 				height = btn_view->getRect().getHeight();
 			}
-			S32 x = llround(i*segment_width);                               
-			S32 y = 0;                                                      
-			LLRect r;                                                               
-			r.setOriginAndSize(x, y, btn_width, height);                    
-			btn_view->setRect(r);                                           
+
+			LLRect r;
+
+			if (btn_view->getName() == "chat_btn")
+			{
+				r.setOriginAndSize(x, 0, btn_view->getRect().getWidth(), height);
+				x += btn_view->getRect().getWidth() + pad;
+			}
+			else
+			{
+				r.setOriginAndSize(x, 0, btn_width, height);
+				x += segment_width;
+			}
+
+			btn_view->setOrigin(r.mLeft, r.mBottom);
+			btn_view->reshape(r.getWidth(), r.getHeight());
 			i--;                                                            
 		}
 	}                                                                       
@@ -321,6 +340,7 @@ void LLToolBar::refresh()
 
 	childSetEnabled("build_btn", gParcelMgr->agentCanBuild() );
 
+
 	// Check to see if we're in build mode
 	BOOL build_mode = gToolMgr->inEdit();
 	// And not just clicking on a scripted object
@@ -329,13 +349,135 @@ void LLToolBar::refresh()
 		build_mode = FALSE;
 	}
 	gSavedSettings.setBOOL("BuildBtnState", build_mode);
+
+	updateCommunicateList();
+}
+
+void LLToolBar::updateCommunicateList()
+{
+	LLFlyoutButton* communicate_button = (LLFlyoutButton*)getChildByName("communicate_btn", TRUE);
+	if (communicate_button)
+	{
+		LLSD selected = communicate_button->getValue();
+
+		communicate_button->removeall();
+
+		LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater();
+		LLScrollListItem* itemp = NULL;
+
+		itemp = communicate_button->add(LLFloaterMyFriends::getInstance()->getShortTitle(), LLSD("contacts"), ADD_TOP);
+		if (LLFloaterMyFriends::getInstance() == frontmost_floater)
+		{
+			((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD);
+			// make sure current tab is selected in list
+			if (selected.isUndefined())
+			{
+				selected = itemp->getValue();
+			}
+		}
+		itemp = communicate_button->add(LLFloaterChat::getInstance()->getShortTitle(), LLSD("local chat"), ADD_TOP);
+		if (LLFloaterChat::getInstance() == frontmost_floater)
+		{
+			((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD);
+			if (selected.isUndefined())
+			{
+				selected = itemp->getValue();
+			}
+		}
+		communicate_button->addSeparator(ADD_TOP);
+		communicate_button->add(getUIString("Redock Windows"), LLSD("redock"), ADD_TOP);
+		communicate_button->addSeparator(ADD_TOP);
+		communicate_button->add(LLFloaterMute::getInstance()->getShortTitle(), LLSD("mute list"), ADD_TOP);
+		
+		std::set<LLViewHandle>::const_iterator floater_handle_it;
+
+		if (gIMMgr->getIMFloaterHandles().size() > 0)
+		{
+			communicate_button->addSeparator(ADD_TOP);
+		}
+
+		for(floater_handle_it = gIMMgr->getIMFloaterHandles().begin(); floater_handle_it != gIMMgr->getIMFloaterHandles().end(); ++floater_handle_it)
+		{
+			LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*floater_handle_it);
+			if (im_floaterp)
+			{
+				LLString floater_title = im_floaterp->getNumUnreadMessages() > 0 ? "*" : "";
+				floater_title.append(im_floaterp->getShortTitle());
+				itemp = communicate_button->add(floater_title, im_floaterp->getSessionID(), ADD_TOP);
+				if (im_floaterp  == frontmost_floater)
+				{
+					((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD);
+					if (selected.isUndefined())
+					{
+						selected = itemp->getValue();
+					}
+				}
+			}
+		}
+
+		communicate_button->setToggleState(gSavedSettings.getBOOL("ShowCommunicate"));
+		communicate_button->setValue(selected);
+	}
 }
 
 
 // static
-void LLToolBar::onClickCommunicate(void* user_data)
+void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, void* user_data)
 {
-	LLFloaterChatterBox::toggleInstance(LLSD());
+	LLToolBar* toolbar = (LLToolBar*)user_data;
+	LLFlyoutButton* communicate_button = (LLFlyoutButton*)toolbar->getChildByName("communicate_btn", TRUE);
+	
+	LLSD selected_option = communicate_button->getValue();
+    
+	if (selected_option.asString() == "contacts")
+	{
+		LLFloaterMyFriends::showInstance();
+	}
+	else if (selected_option.asString() == "local chat")
+	{
+		LLFloaterChat::showInstance();
+	}
+	else if (selected_option.asString() == "redock")
+	{
+		LLFloaterChatterBox::getInstance()->addFloater(LLFloaterMyFriends::getInstance(), FALSE);
+		LLFloaterChatterBox::getInstance()->addFloater(LLFloaterChat::getInstance(), FALSE);
+		LLUUID session_to_show;
+		
+		std::set<LLViewHandle>::const_iterator floater_handle_it;
+		for(floater_handle_it = gIMMgr->getIMFloaterHandles().begin(); floater_handle_it != gIMMgr->getIMFloaterHandles().end(); ++floater_handle_it)
+		{
+			LLFloater* im_floaterp = LLFloater::getFloaterByHandle(*floater_handle_it);
+			if (im_floaterp)
+			{
+				if (im_floaterp->isFrontmost())
+				{
+					session_to_show = ((LLFloaterIMPanel*)im_floaterp)->getSessionID();
+				}
+				LLFloaterChatterBox::getInstance()->addFloater(im_floaterp, FALSE);
+			}
+		}
+
+		LLFloaterChatterBox::showInstance(session_to_show);
+	}
+	else if (selected_option.asString() == "mute list")
+	{
+		LLFloaterMute::showInstance();
+	}
+	else if (selected_option.isUndefined()) // user just clicked the communicate button, treat as toggle
+	{
+		if (LLFloaterChatterBox::getInstance()->getFloaterCount() == 0)
+		{
+			LLFloaterMyFriends::toggleInstance();
+		}
+		else
+		{
+			LLFloaterChatterBox::toggleInstance();
+		}
+	}
+	else // otherwise selection_option is a specific IM session id
+	{
+		LLFloaterChatterBox::showInstance(selected_option);
+	}
 }
 
 
diff --git a/indra/newview/lltoolbar.h b/indra/newview/lltoolbar.h
index c43c80b095fd88218daae0d002c7446831a30d75..85adba8c550b684d7483078b8927436d902e3db3 100644
--- a/indra/newview/lltoolbar.h
+++ b/indra/newview/lltoolbar.h
@@ -47,7 +47,7 @@ class LLToolBar
 :	public LLPanel
 {
 public:
-	LLToolBar(const std::string& name, const LLRect& rect );
+	LLToolBar();
 	~LLToolBar();
 
 	/*virtual*/ BOOL postBuild();
@@ -70,7 +70,7 @@ class LLToolBar
 	void refresh();
 
 	// callbacks
-	static void onClickCommunicate(void*);
+	static void onClickCommunicate(LLUICtrl*, void*);
 	static void onClickChat(void* data);
 	static void onClickAppearance(void* data);
 	static void onClickClothing(void* data);
@@ -85,9 +85,14 @@ class LLToolBar
 
 	static F32 sInventoryAutoOpenTime;
 
+private:
+	void updateCommunicateList();
+
+
 private:
 	BOOL		mInventoryAutoOpen;
 	LLFrameTimer mInventoryAutoOpenTimer;
+	S32			mNumUnreadIMs;
 #if LL_DARWIN
 	LLFakeResizeHandle *mResizeHandle;
 #endif // LL_DARWIN
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index d26bdab921be969c58809c6fa2e855451a290c98..a27053faa389849608867e6bd71041aa52299162 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -216,7 +216,7 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
 	// Play creation sound
 	if (gAudiop)
 	{
-		F32 volume = gSavedSettings.getF32("AudioLevelUI");
+		F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
 		gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), volume);
 	}
 
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index ac90a06a570156683afce9d54c2a33014a40f87d..8e742bd655f35ba6b73c3fec84254822edf0edbb 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -122,8 +122,10 @@ void audio_update_volume(bool force_update)
 	if (gAudiop) 
 	{		
 		F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
+		BOOL music_muted = gSavedSettings.getBOOL("MuteMusic");
 		music_volume = mute_volume * master_volume * (music_volume*music_volume);
-		gAudiop->setInternetStreamGain ( music_volume );
+		gAudiop->setInternetStreamGain ( music_muted ? 0.f : music_volume );
+	
 	}
 
 	// Streaming Media
@@ -131,7 +133,8 @@ void audio_update_volume(bool force_update)
 	{
 		F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
 		media_volume = mute_volume * master_volume * (media_volume*media_volume);
-		LLMediaEngine::getInstance()->setVolume(media_volume);
+		BOOL media_muted = gSavedSettings.getBOOL("MuteMedia");
+		LLMediaEngine::getInstance()->setVolume(media_muted ? 0.f : media_volume);
 	}
 
 	// Voice
@@ -139,8 +142,9 @@ void audio_update_volume(bool force_update)
 	{
 		F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
 		voice_volume = mute_volume * master_volume * voice_volume;
-		gVoiceClient->setVoiceVolume(voice_volume);
-		gVoiceClient->setMicGain(gSavedSettings.getF32("AudioLevelMic"));
+		BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice");
+		gVoiceClient->setVoiceVolume(voice_mute ? 0.f : voice_volume);
+		gVoiceClient->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
 
 		if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
 		{
@@ -206,7 +210,7 @@ void audio_update_wind(bool force_update)
 		// don't use the setter setMaxWindGain() because we don't
 		// want to screw up the fade-in on startup by setting actual source gain
 		// outside the fade-in.
-		gAudiop->mMaxWindGain = gSavedSettings.getF32("AudioLevelAmbient");
+		gAudiop->mMaxWindGain = gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient");
 		
 		last_camera_water_height = camera_water_height;
 		gAudiop->updateWind(gRelativeWindVec, camera_water_height);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2fccdcd153c3aad4294693e8c13d69760726c9fb..fdc0047f95671144d6b7af0b802e78090c8d3b96 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2103,7 +2103,7 @@ class LLObjectMute : public view_listener_t
 		else
 		{
 			gMuteListp->add(mute);
-			gFloaterMute->show();
+			LLFloaterMute::showInstance();
 		}
 		
 		return true;
@@ -5309,7 +5309,7 @@ class LLShowFloater : public view_listener_t
 		}
 		else if (floater_name == "mute list")
 		{
-			LLFloaterMute::toggle(NULL);
+			LLFloaterMute::toggleInstance();
 		}
 		else if (floater_name == "camera controls")
 		{
@@ -5355,7 +5355,7 @@ class LLShowFloater : public view_listener_t
 		}
 		else if (floater_name == "about region")
 		{
-			LLFloaterRegionInfo::show((void *)NULL);
+			LLFloaterRegionInfo::showInstance();
 		}
 		else if (floater_name == "grid options")
 		{
@@ -5447,7 +5447,7 @@ class LLFloaterVisible : public view_listener_t
 		}
 		else if (floater_name == "mute list")
 		{
-			new_value = LLFloaterMute::visible(NULL);
+			new_value = LLFloaterMute::instanceVisible();
 		}
 		else if (floater_name == "camera controls")
 		{
@@ -6963,13 +6963,12 @@ void handle_grab_texture(void* data)
 			if(view)
 			{
 				LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
-				LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();
 
 				view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO);
 				view->getPanel()->openSelected();
 				//LLInventoryView::dumpSelectionInformation((void*)view);
 				// restore keyboard focus
-				gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
+				gFocusMgr.setKeyboardFocus(focus_ctrl);
 			}
 		}
 		else
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ebb0da016fa8495a4dec981e425182afa131e085..8a4cd16c0800b03ca67024dcb7094aedae5bf95d 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -888,10 +888,8 @@ void open_offer(const std::vector<LLUUID>& items, const std::string& from_name)
 		//highlight item
 
 		LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
-		LLFocusMgr::FocusLostCallback callback;
-		callback = gFocusMgr.getFocusCallback();
 		view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
-		gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
+		gFocusMgr.setKeyboardFocus(focus_ctrl);
 	}
 }
 
@@ -920,7 +918,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
 	LLMute mute(blocked_id, from_name, type);
 	if (gMuteListp->add(mute))
 	{
-		gFloaterMute->show();
+		LLFloaterMute::showInstance();
 		gFloaterMute->selectMute(blocked_id);
 	}
 
@@ -2192,9 +2190,13 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 	BOOL is_linden = FALSE;
 	if (gMuteListp)
 	{
-		is_muted = gMuteListp->isMuted(from_id, from_name, LLMute::flagTextChat)
-				   || gMuteListp->isMuted(owner_id, LLMute::flagTextChat);
-		is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && gMuteListp->isLinden(from_name);
+		is_muted = gMuteListp->isMuted(
+			from_id,
+			from_name,
+			LLMute::flagTextChat) 
+			|| gMuteListp->isMuted(owner_id, LLMute::flagTextChat);
+		is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
+			gMuteListp->isLinden(from_name);
 	}
 
 	BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
@@ -2235,7 +2237,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 		BOOL visible_in_chat_bubble = FALSE;
 		std::string verb;
 
-		color.setVec(1,1,1,1);
+		color.setVec(1.f,1.f,1.f,1.f);
 		msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, DB_CHAT_MSG_BUF_SIZE, mesg);
 
 		BOOL ircstyle = FALSE;
@@ -3332,7 +3334,7 @@ void process_sound_trigger(LLMessageSystem *msg, void **)
 		return;
 	}
 
-	F32 volume = gain * gSavedSettings.getF32("AudioLevelSFX");
+	F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (gain * gSavedSettings.getF32("AudioLevelSFX"));
 	gAudiop->triggerSound(sound_id, owner_id, volume, pos_global);
 }
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 4c6f27944f3c4e20358c3b1fbf47baa4f0aaa71f..924326379469fecd9448f89bbb572dd4a485a8fc 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2717,7 +2717,7 @@ BOOL LLViewerObject::updateLOD()
 	// Update volume of looping sounds
 	if (mAudioSourcep && mAudioSourcep->isLoop())
 	{
-		F32 volume = mAudioGain * gSavedSettings.getF32("AudioLevelSFX");
+		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (mAudioGain * gSavedSettings.getF32("AudioLevelSFX"));
 		mAudioSourcep->setGain(volume);
 	}
 	return FALSE;
@@ -4228,7 +4228,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow
 	{
 		BOOL queue = flags & LL_SOUND_FLAG_QUEUE;
 		mAudioGain = gain;
-		F32 volume = gain * gSavedSettings.getF32("AudioLevelSFX");
+		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : gain * gSavedSettings.getF32("AudioLevelSFX");
 		mAudioSourcep->setGain(volume);
 		mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP);
 		mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER);
@@ -4267,7 +4267,7 @@ void LLViewerObject::adjustAudioGain(const F32 gain)
 	if (mAudioSourcep)
 	{
 		mAudioGain = gain;
-		F32 volume = mAudioGain * gSavedSettings.getF32("AudioLevelSFX");
+		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : mAudioGain * gSavedSettings.getF32("AudioLevelSFX");
 		mAudioSourcep->setGain(volume);
 	}
 }
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index b0d1d3daca637cd74db8bd3afb18ead22344defc..0ffa37525f82200be47a3205aeb005348c0ef024 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -266,23 +266,6 @@ void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out,
 	*dwell_out = dwell;
 }
 
-void LLViewerParcelMgr::getPrimInfo(S32 &sw_max, S32 &sw_total, S32 &max, S32 &total, S32 &owner, S32 &group, S32 &other, S32& selected, F32 &parcel_object_bonus, S32 &other_clean)
-{
-	if (mSelected && mCurrentParcel)
-	{
-		sw_max = mCurrentParcel->getSimWideMaxPrimCapacity();
-		sw_total = mCurrentParcel->getSimWidePrimCount();
-		max = llround(mCurrentParcel->getMaxPrimCapacity()*mCurrentParcel->getParcelPrimBonus());
-		total = mCurrentParcel->getPrimCount();
-		owner = mCurrentParcel->getOwnerPrimCount();
-		group = mCurrentParcel->getGroupPrimCount();
-		other = mCurrentParcel->getOtherPrimCount();
-		selected = mCurrentParcel->getSelectedPrimCount();
-		parcel_object_bonus = mCurrentParcel->getParcelPrimBonus();
-		other_clean = mCurrentParcel->getCleanOtherTime();
-	}
-}
-
 S32 LLViewerParcelMgr::getSelectedArea() const
 {
 	S32 rv = 0;
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index 2dd4f2816964e3f762c82aab6ee5b689a2c9d9ae..640c8c5c57cdf2277123f9637149ae5f47a605bf 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -134,8 +134,6 @@ class LLViewerParcelMgr
 
 	void	getDisplayInfo(S32* area, S32* claim, S32* rent, BOOL* for_sale, F32* dwell);
 
-	void	getPrimInfo(S32 &sw_max, S32 &sw_total, S32 &max, S32 &total, S32 &owner, S32 &group, S32 &other, S32& selected, F32 &parcel_object_bonus, S32 &other_clean);
-
 	// Returns selected area
 	S32 getSelectedArea() const;
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index ad4b6fd616ca9f01b3727da544600714a57df21d..6001cd3e58f4c3410664dac468f5c8191d1013d1 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -366,6 +366,11 @@ F32 LLViewerRegion::getWaterHeight() const
 	return mLandp->getWaterHeight();
 }
 
+BOOL LLViewerRegion::isVoiceEnabled() const
+{
+	return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE);
+}
+
 void LLViewerRegion::setRegionFlags(U32 flags)
 {
 	mRegionFlags = flags;
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index a0953e561e9069399efcd9ba3acee75075d476cb..e42c0015df441de28aca9a7647ae46364d6bc960 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -109,6 +109,8 @@ class LLViewerRegion
 	void setWaterHeight(F32 water_level);
 	F32 getWaterHeight() const;
 
+	BOOL isVoiceEnabled() const;
+
 	void setBillableFactor(F32 billable_factor) { mBillableFactor = billable_factor; }
 	F32 getBillableFactor() 		const 	{ return mBillableFactor; }
 
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 81de1eb9a8c0fde9b7c02e3e86dd3cb03a8a0799..18f07efb4444db5c31baf056f63a590099e59c46 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -605,54 +605,50 @@ void LLViewerTextEditor::makePristine()
 
 BOOL LLViewerTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
 {
-	if (pointInView(x, y) && getVisible())
+	for (child_list_const_iter_t child_iter = getChildList()->begin();
+			child_iter != getChildList()->end(); ++child_iter)
 	{
-		for (child_list_const_iter_t child_iter = getChildList()->begin();
-			 child_iter != getChildList()->end(); ++child_iter)
+		LLView *viewp = *child_iter;
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
 		{
-			LLView *viewp = *child_iter;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
-			{
-				return TRUE;
-			}
+			return TRUE;
 		}
+	}
+
+	if( mSegments.empty() )
+	{
+		return TRUE;
+	}
 
-		if( mSegments.empty() )
+	LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
+	if( cur_segment )
+	{
+		BOOL has_tool_tip = FALSE;
+		if( cur_segment->getStyle().getIsEmbeddedItem() )
 		{
-			return TRUE;
+			LLWString wtip;
+			has_tool_tip = getEmbeddedItemToolTipAtPos(cur_segment->getStart(), wtip);
+			msg = wstring_to_utf8str(wtip);
 		}
-
-		LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
-		if( cur_segment )
+		else
 		{
-			BOOL has_tool_tip = FALSE;
-			if( cur_segment->getStyle().getIsEmbeddedItem() )
-			{
-				LLWString wtip;
-				has_tool_tip = getEmbeddedItemToolTipAtPos(cur_segment->getStart(), wtip);
-				msg = wstring_to_utf8str(wtip);
-			}
-			else
-			{
-				has_tool_tip = cur_segment->getToolTip( msg );
-			}
-			if( has_tool_tip )
-			{
-				// Just use a slop area around the cursor
-				// Convert rect local to screen coordinates
-				S32 SLOP = 8;
-				localPointToScreen( 
-					x - SLOP, y - SLOP, 
-					&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
-				sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
-				sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
-			}
+			has_tool_tip = cur_segment->getToolTip( msg );
+		}
+		if( has_tool_tip )
+		{
+			// Just use a slop area around the cursor
+			// Convert rect local to screen coordinates
+			S32 SLOP = 8;
+			localPointToScreen( 
+				x - SLOP, y - SLOP, 
+				&(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+			sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
+			sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
 		}
-		return TRUE;
 	}
-	return FALSE;
+	return TRUE;
 }
 
 BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
@@ -759,9 +755,9 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 		handled = TRUE;
 	}
 
-	if (mTakesFocus)
+	if (hasTabStop())
 	{
-		setFocus( TRUE );
+		setFocus(TRUE);
 		handled = TRUE;
 	}
 
@@ -1016,11 +1012,7 @@ BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 			}
 		}
 
-		if (mTakesFocus)
-		{
-			setFocus( TRUE );
-		}
-		
+	
 		setCursorAtLocalPos( x, y, FALSE );
 		deselect();
 
@@ -1390,7 +1382,7 @@ void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item )
 	const F32 SOUND_GAIN = 1.0f;
 	if(gAudiop)
 	{
-		F32 volume = SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX");
+		F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX"));
 		gAudiop->triggerSound(item->getAssetUUID(), gAgentID, volume, lpos_global);
 	}
 	showCopyToInvDialog( item );
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index a3611b227299880bd6f8036c0d8e259553ccc338..4c960833377ecfbe0a9fbc9afbb278e3b49eb4d8 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -266,6 +266,8 @@ const S32 PICK_DIAMETER = 2 * PICK_HALF_WIDTH+1;
 
 const F32 MIN_DISPLAY_SCALE = 0.85f;
 
+const S32 CONSOLE_BOTTOM_PAD = 20;
+
 #ifdef SABINRIG
 /// ALL RIG STUFF
 bool rigControl = false;
@@ -663,18 +665,17 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
 
 	// Topmost view gets a chance before the hierarchy
 	LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-	BOOL mouse_over_top_ctrl = FALSE;
 	if (top_ctrl)
 	{
 		S32 local_x, local_y;
 		top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
 		if (top_ctrl->pointInView(local_x, local_y))
 		{
-			mouse_over_top_ctrl = TRUE;
-			if(top_ctrl->handleMouseDown(local_x, local_y, mask)) 
-			{
-				return TRUE;
-			}
+			return top_ctrl->handleMouseDown(local_x, local_y, mask);
+		}
+		else
+		{
+			setTopCtrl(NULL);
 		}
 	}
 
@@ -686,11 +687,6 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
 			llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
 			LLView::sMouseHandlerMessage = "";
 		}
-		if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-		{
-			// always defocus top view if we click off of it
-			top_ctrl->setFocus(FALSE);
-		}
 		return TRUE;
 	}
 	else if (LLView::sDebugMouseHandling)
@@ -698,12 +694,6 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
 		llinfos << "Left Mouse Down not handled by view" << llendl;
 	}
 
-	if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-	{
-		// always defocus top view if we click off of it
-		top_ctrl->setFocus(FALSE);
-	}
-
 	if (gDisconnected)
 	{
 		return FALSE;
@@ -716,7 +706,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
 			// This is necessary to force clicks in the world to cause edit
 			// boxes that might have keyboard focus to relinquish it, and hence
 			// cause a commit to update their value.  JC
-			gFocusMgr.setKeyboardFocus(NULL, NULL);
+			gFocusMgr.setKeyboardFocus(NULL);
 			return TRUE;
 		}
 	}
@@ -760,18 +750,17 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK ma
 
 	// Check for hit on UI.
 	LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-	BOOL mouse_over_top_ctrl = FALSE;
 	if (top_ctrl)
 	{
 		S32 local_x, local_y;
 		top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
 		if (top_ctrl->pointInView(local_x, local_y))
 		{
-			mouse_over_top_ctrl = TRUE;
-			if(top_ctrl->handleDoubleClick(local_x, local_y, mask))
-			{
-				return TRUE;
-			}
+			return top_ctrl->handleDoubleClick(local_x, local_y, mask);
+		}
+		else
+		{
+			setTopCtrl(NULL);
 		}
 	}
 
@@ -782,11 +771,6 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK ma
 			llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
 			LLView::sMouseHandlerMessage = "";
 		}
-		if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-		{
-			// always defocus top view if we click off of it
-			top_ctrl->setFocus(FALSE);
-		}
 		return TRUE;
 	}
 	else if (LLView::sDebugMouseHandling)
@@ -794,12 +778,6 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK ma
 		llinfos << "Left Mouse Down not handled by view" << llendl;
 	}
 
-	if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-	{
-		// always defocus top view if we click off of it
-		top_ctrl->setFocus(FALSE);
-	}
-
 		// Why is this here?  JC 9/3/2002
 	if (gNoRender) 
 	{
@@ -970,18 +948,17 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK
 	}
 
 	LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
-	BOOL mouse_over_top_ctrl = FALSE;
 	if (top_ctrl)
 	{
 		S32 local_x, local_y;
 		top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
 		if (top_ctrl->pointInView(local_x, local_y))
 		{
-			mouse_over_top_ctrl = TRUE;
-			if(top_ctrl->handleRightMouseDown(local_x, local_y, mask)) 
-			{
-				return TRUE;
-			}
+			return top_ctrl->handleRightMouseDown(local_x, local_y, mask);
+		}
+		else
+		{
+			setTopCtrl(NULL);
 		}
 	}
 
@@ -992,11 +969,6 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK
 			llinfos << "Right Mouse Down" << LLView::sMouseHandlerMessage << llendl;
 			LLView::sMouseHandlerMessage = "";
 		}
-		if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-		{
-			// always defocus top view if we click off of it
-			top_ctrl->setFocus(FALSE);
-		}
 		return TRUE;
 	}
 	else if (LLView::sDebugMouseHandling)
@@ -1004,12 +976,6 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK
 		llinfos << "Right Mouse Down not handled by view" << llendl;
 	}
 
-	if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
-	{
-		// always defocus top view if we click off of it
-		top_ctrl->setFocus(FALSE);
-	}
-
 	if (gToolMgr)
 	{
 		if(gToolMgr->getCurrentTool()->handleRightMouseDown( x, y, mask ) )
@@ -1017,7 +983,7 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK
 			// This is necessary to force clicks in the world to cause edit
 			// boxes that might have keyboard focus to relinquish it, and hence
 			// cause a commit to update their value.  JC
-			gFocusMgr.setKeyboardFocus(NULL, NULL);
+			gFocusMgr.setKeyboardFocus(NULL);
 			return TRUE;
 		}
 	}
@@ -1266,7 +1232,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 
 	// JC - Leave keyboard focus, so if you're popping in and out editing
 	// a script, you don't have to click in the editor again and again.
-	// gFocusMgr.setKeyboardFocus( NULL, NULL );
+	// gFocusMgr.setKeyboardFocus( NULL );
 	gShowTextEditCursor = FALSE;
 
 	// If losing focus while keys are down, reset them.
@@ -1746,14 +1712,6 @@ void LLViewerWindow::initBase()
 	gDebugView->setVisible(TRUE);
 	mRootView->addChild(gDebugView);
 
-	// HUD elements just below floaters
-	LLRect hud_rect = full_window;
-	hud_rect.mTop -= 24;
-	hud_rect.mBottom += STATUS_BAR_HEIGHT;
-	gHUDView = new LLHUDView("hud_view", hud_rect);
-	gHUDView->setFollowsAll();
-	mRootView->addChild(gHUDView);
-
 	// Add floater view at the end so it will be on top, and give it tab priority over others
 	mRootView->addChild(gFloaterView, -1);
 	mRootView->addChild(gSnapshotFloaterView);
@@ -1871,27 +1829,10 @@ void LLViewerWindow::initWorldUI()
 	S32 width = mRootView->getRect().getWidth();
 	LLRect full_window(0, height, width, 0);
 
-	if ( gToolBar == NULL )			// Don't re-enter if objects are alreay created
+	if ( gBottomPanel == NULL )			// Don't re-enter if objects are alreay created
 	{
-		LLRect bar_rect(-1, STATUS_BAR_HEIGHT, width+1, -1);
-		gToolBar = new LLToolBar("toolbar", bar_rect);
-
-		LLRect chat_bar_rect(-1,CHAT_BAR_HEIGHT, width+1, -1);
-		chat_bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
-		gChatBar = new LLChatBar("chat", chat_bar_rect);
-
-		bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
-		bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
-		gOverlayBar = new LLOverlayBar("overlay", bar_rect);
-
 		// panel containing chatbar, toolbar, and overlay, over floaters
-		LLRect bottom_rect(-1, 2*STATUS_BAR_HEIGHT + CHAT_BAR_HEIGHT, width+1, -1);
-		gBottomPanel = new LLBottomPanel("bottom panel", bottom_rect);
-
-		// the order here is important
-		gBottomPanel->addChild(gChatBar);
-		gBottomPanel->addChild(gToolBar);
-		gBottomPanel->addChild(gOverlayBar);
+		gBottomPanel = new LLBottomPanel(mRootView->getRect());
 		mRootView->addChild(gBottomPanel);
 
 		// View for hover information
@@ -1933,8 +1874,7 @@ void LLViewerWindow::initWorldUI()
 		mRootView->addChild(gMorphView);
 		gMorphView->setVisible(FALSE);
 
-		gFloaterMute = new LLFloaterMute();
-		gFloaterMute->setVisible(FALSE);
+		gFloaterMute = LLFloaterMute::getInstance();
 
 		LLWorldMapView::initClass();
 
@@ -2450,6 +2390,12 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 		if(LLMenuGL::getKeyboardMode())
 			LLMenuGL::setKeyboardMode(FALSE);
 
+		if (gFocusMgr.getTopCtrl())
+		{
+			gFocusMgr.setTopCtrl(NULL);
+			return TRUE;
+		}
+
 		// *TODO: get this to play well with mouselook and hidden
 		// cursor modes, etc, and re-enable.
 		//if (gFocusMgr.getMouseCapture())
@@ -2979,23 +2925,9 @@ BOOL LLViewerWindow::handlePerFrameHover()
 	}
 
 	// Update rectangles for the various toolbars
-	if (gToolBar && gChatBar && gOverlayBar && gNotifyBoxView && gConsole)
+	if (gOverlayBar && gNotifyBoxView && gConsole)
 	{
 		LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1);
-		if (gToolBar->getVisible())
-		{
-			gToolBar->setRect(bar_rect);
-			bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
-		}
-
-		if (gChatBar->getVisible())
-		{
-			// fix up the height
-			LLRect chat_bar_rect = bar_rect;
-			chat_bar_rect.mTop = chat_bar_rect.mBottom + CHAT_BAR_HEIGHT + 1;
-			gChatBar->setRect(chat_bar_rect);
-			bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
-		}
 
 		LLRect notify_box_rect = gNotifyBoxView->getRect();
 		notify_box_rect.mBottom = bar_rect.mBottom;
@@ -3015,42 +2947,16 @@ BOOL LLViewerWindow::handlePerFrameHover()
 
 		if (gOverlayBar->getVisible())
 		{
-			LLRect overlay_rect = bar_rect;
-			overlay_rect.mTop = overlay_rect.mBottom + OVERLAY_BAR_HEIGHT;
-
-			// Fitt's Law: Push buttons flush with bottom of screen if
-			// nothing else visible.
-			if (!gToolBar->getVisible()
-				&& !gChatBar->getVisible())
-			{
-				// *NOTE: this is highly depenent on the XML
-				// describing the position of the buttons
-				overlay_rect.translate(0, 0);
-			}
-
-			gOverlayBar->setRect(overlay_rect);
-			gOverlayBar->updateRect();
-			bar_rect.translate(0, gOverlayBar->getRect().getHeight());
-
-			gFloaterView->setSnapOffsetBottom(OVERLAY_BAR_HEIGHT);
+			gFloaterView->setSnapOffsetBottom(gHUDView->getRect().mBottom);
 		}
 		else
 		{
 			gFloaterView->setSnapOffsetBottom(0);
 		}
 
-		// fix rectangle of bottom panel focus indicator
-		if(gBottomPanel && gBottomPanel->getFocusIndicator())
-		{
-			LLRect focus_rect = gBottomPanel->getFocusIndicator()->getRect();
-			focus_rect.mTop = (gToolBar->getVisible() ? STATUS_BAR_HEIGHT : 0) + 
-				(gChatBar->getVisible() ? CHAT_BAR_HEIGHT : 0) - 2;
-			gBottomPanel->getFocusIndicator()->setRect(focus_rect);
-		}
-
 		// Always update console
 		LLRect console_rect = gConsole->getRect();
-		console_rect.mBottom = bar_rect.mBottom + 8;
+		console_rect.mBottom = gHUDView->getRect().mBottom + CONSOLE_BOTTOM_PAD;
 		gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
 		gConsole->setRect(console_rect);
 	}
@@ -3628,13 +3534,6 @@ void LLViewerWindow::performPick()
 			// if you are the parent
 			parent = objectp;
 		}
-		std::vector<LLPointer<LLViewerObject>,std::allocator<LLPointer<LLViewerObject> > > children = parent->getChildren();
-		for( std::vector<LLPointer<LLViewerObject>,std::allocator<LLPointer<LLViewerObject> > >::iterator i= children.begin(); i!= children.end(); ++i )
-		{
-			//go through
-			LLViewerObject* foo = *i;
-			foo->getRotation();
-		}
 		if (objectp->mbCanSelect)
 		{
 			te_offset = (te_offset == 16) ? NO_FACE : te_offset;
@@ -4561,9 +4460,9 @@ void LLViewerWindow::drawMouselookInstructions()
 // These functions are here only because LLViewerWindow used to do the work that gFocusMgr does now.
 // They let other objects continue to work without change.
 
-void LLViewerWindow::setKeyboardFocus(LLUICtrl* new_focus,void (*on_focus_lost)(LLUICtrl* old_focus))
+void LLViewerWindow::setKeyboardFocus(LLUICtrl* new_focus)
 {
-	gFocusMgr.setKeyboardFocus( new_focus, on_focus_lost );
+	gFocusMgr.setKeyboardFocus( new_focus );
 }
 
 LLUICtrl* LLViewerWindow::getKeyboardFocus()
@@ -5033,7 +4932,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 	}
 
 	mIgnoreActivate = FALSE;
-	gFocusMgr.setKeyboardFocus(keyboard_focus, NULL);
+	gFocusMgr.setKeyboardFocus(keyboard_focus);
 	mWantFullscreen = mWindow->getFullscreen();
 	mShowFullscreenProgress = FALSE;
 	
@@ -5233,16 +5132,22 @@ LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename,
 
 ////////////////////////////////////////////////////////////////////////////
 
-LLBottomPanel::LLBottomPanel(const LLString &name, const LLRect &rect) : 
-	LLPanel(name, rect, FALSE),
+LLBottomPanel::LLBottomPanel(const LLRect &rect) : 
+	LLPanel("", rect, FALSE),
 	mIndicator(NULL)
 {
 	// bottom panel is focus root, so Tab moves through the toolbar and button bar, and overlay
 	setFocusRoot(TRUE);
-	// don't capture mouse clicks that don't hit a child
-	setMouseOpaque(FALSE);
-	setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
+	// flag this panel as chrome so buttons don't grab keyboard focus
 	setIsChrome(TRUE);
+
+	mFactoryMap["toolbar"] = LLCallbackMap(createToolBar, NULL);
+	mFactoryMap["overlay"] = LLCallbackMap(createOverlayBar, NULL);
+	mFactoryMap["hud"] = LLCallbackMap(createHUD, NULL);
+	gUICtrlFactory->buildPanel(this, "panel_bars.xml", &getFactoryMap());
+	
+	setOrigin(rect.mLeft, rect.mBottom);
+	reshape(rect.getWidth(), rect.getHeight());
 }
 
 void LLBottomPanel::setFocusIndicator(LLView * indicator)
@@ -5260,3 +5165,25 @@ void LLBottomPanel::draw()
 	}
 	LLPanel::draw();
 }
+
+void* LLBottomPanel::createHUD(void* data)
+{
+	delete gHUDView;
+	gHUDView = new LLHUDView();
+	return gHUDView;
+}
+
+
+void* LLBottomPanel::createOverlayBar(void* data)
+{
+	delete gOverlayBar;
+	gOverlayBar = new LLOverlayBar();
+	return gOverlayBar;
+}
+
+void* LLBottomPanel::createToolBar(void* data)
+{
+	delete gToolBar;
+	gToolBar = new LLToolBar();
+	return gToolBar;
+}
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index faab518879974f850567a052e9fe73d385e34595..36225cb7d33e25eb312e6000c849c399d07eebfa 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -185,7 +185,7 @@ class LLViewerWindow : public LLWindowCallbacks
 	// Handle the application becoming active (frontmost) or inactive
 	//BOOL			handleActivate(BOOL activate);
 
-	void			setKeyboardFocus(LLUICtrl* new_focus,void (*on_focus_lost)(LLUICtrl* old_focus));		// new_focus = NULL to release the focus.
+	void			setKeyboardFocus(LLUICtrl* new_focus);		// new_focus = NULL to release the focus.
 	LLUICtrl*		getKeyboardFocus();	
 	BOOL			hasKeyboardFocus( const LLUICtrl* possible_focus ) const;
 	BOOL			childHasKeyboardFocus( const LLView* parent ) const;
@@ -363,10 +363,15 @@ class LLViewerWindow : public LLWindowCallbacks
 class LLBottomPanel : public LLPanel
 {
 public:
-	LLBottomPanel(const LLString& name, const LLRect& rect);
+	LLBottomPanel(const LLRect& rect);
 	void setFocusIndicator(LLView * indicator);
 	LLView * getFocusIndicator() { return mIndicator; }
 	/*virtual*/ void draw();
+
+	static void* createHUD(void* data);
+	static void* createOverlayBar(void* data);
+	static void* createToolBar(void* data);
+
 protected:
 	LLView * mIndicator;
 };
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index fc159ddc48ef614132486165ba82665102bc7596..c6a3ff192b9f848c7d3b918b420d1cadebcec241 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3426,7 +3426,7 @@ void LLVOAvatar::updateCharacter(LLAgent &agent)
 //							AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED,
 //							AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN );
 
-			F32 gain = .30f * gSavedSettings.getF32("AudioLevelAmbient");
+			F32 gain = gSavedSettings.getBOOL("MuteAmbient") ? 0.f : (.30f * gSavedSettings.getF32("AudioLevelAmbient"));
 			LLUUID& step_sound_id = getStepSound();
 
 			LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
@@ -4401,7 +4401,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL
 					//else
 					{
 						LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping"));
-						F32 volume = gSavedSettings.getF32("AudioLevelSFX");
+						F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX");
 						gAudiop->triggerSound(sound_id, getID(), volume, char_pos_global);
 					}
 				}
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index cf6b13e74ca9f605f0f93ec698689accacf22bae..1cbb1adadad64b97e5619660e0aef926fb3da442 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -43,7 +43,6 @@
 #include "llcallbacklist.h"
 #include "llviewerregion.h"
 #include "llviewernetwork.h"		// for gGridChoice
-#include "llfloateractivespeakers.h"	// for LLSpeakerMgr
 #include "llbase64.h"
 #include "llviewercontrol.h"
 #include "llkeyboard.h"
@@ -532,7 +531,7 @@ void LLVivoxProtocolParser::CharData(const char *buffer, int length)
 
 void LLVivoxProtocolParser::processResponse(std::string tag)
 {
-//	llinfos << tag << llendl;
+	//llinfos << tag << llendl;
 
 	if (isEvent)
 	{
@@ -768,7 +767,7 @@ static HANDLE sGatewayHandle = 0;
 static bool isGatewayRunning()
 {
 	bool result = false;
-	if(sGatewayHandle != 0)
+	if(sGatewayHandle != 0)		
 	{
 		DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0);
 		if(waitresult != WAIT_OBJECT_0)
@@ -854,7 +853,7 @@ LLVoiceClient::LLVoiceClient()
 	setPTTKey(keyString);
 	mPTTIsToggle = gSavedSettings.getBOOL("PushToTalkToggle");
 	mEarLocation = gSavedSettings.getS32("VoiceEarLocation");
-	setVoiceVolume(gSavedSettings.getF32("AudioLevelVoice"));
+	setVoiceVolume(gSavedSettings.getBOOL("MuteVoice") ? 0.f : gSavedSettings.getF32("AudioLevelVoice"));
 	std::string captureDevice = gSavedSettings.getString("VoiceInputAudioDevice");
 	setCaptureDevice(captureDevice);
 	std::string renderDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
@@ -876,7 +875,6 @@ LLVoiceClient::LLVoiceClient()
 	mTuningMicVolumeDirty = true;
 	mTuningSpeakerVolume = 0;
 	mTuningSpeakerVolumeDirty = true;
-	mTuningCaptureRunning = false;
 					
 	//  gMuteListp isn't set up at this point, so we defer this until later.
 //	gMuteListp->addObserver(&mutelist_listener);
@@ -1138,14 +1136,15 @@ const char *LLVoiceClient::state2string(LLVoiceClient::state inState)
 		CASE(stateConnectorStart);
 		CASE(stateConnectorStarting);
 		CASE(stateConnectorStarted);
-		CASE(stateMicTuningNoLogin);
 		CASE(stateLoginRetry);
 		CASE(stateLoginRetryWait);
 		CASE(stateNeedsLogin);
 		CASE(stateLoggingIn);
 		CASE(stateLoggedIn);
 		CASE(stateNoChannel);
-		CASE(stateMicTuningLoggedIn);
+		CASE(stateMicTuningStart);
+		CASE(stateMicTuningRunning);
+		CASE(stateMicTuningStop);
 		CASE(stateSessionCreate);
 		CASE(stateSessionConnect);
 		CASE(stateJoiningSession);
@@ -1164,6 +1163,7 @@ const char *LLVoiceClient::state2string(LLVoiceClient::state inState)
 		CASE(stateJoinSessionFailed);
 		CASE(stateJoinSessionFailedWaiting);
 		CASE(stateJail);
+		CASE(stateMicTuningNoLogin);
 	}
 
 #undef CASE
@@ -1483,7 +1483,8 @@ void LLVoiceClient::stateMachine()
 			}
 			else if(mTuningMode)
 			{
-				setState(stateMicTuningNoLogin);
+				mTuningExitState = stateConnectorStart;
+				setState(stateMicTuningStart);
 			}
 		break;
 		
@@ -1515,24 +1516,63 @@ void LLVoiceClient::stateMachine()
 			}
 		break;
 				
-		case stateMicTuningNoLogin:
-		case stateMicTuningLoggedIn:
-		{
-			// Both of these behave essentially the same.  The only difference is where the exit transition goes to.
-			if(mTuningMode && mVoiceEnabled && !mSessionTerminateRequested)
-			{	
-				if(!mTuningCaptureRunning)
+		case stateMicTuningStart:
+			if(mUpdateTimer.hasExpired())
+			{
+				if(mCaptureDeviceDirty || mRenderDeviceDirty)
+				{
+					// These can't be changed while in tuning mode.  Set them before starting.
+					std::ostringstream stream;
+
+					if(mCaptureDeviceDirty)
+					{
+						buildSetCaptureDevice(stream);
+					}
+
+					if(mRenderDeviceDirty)
+					{
+						buildSetRenderDevice(stream);
+					}
+
+					mCaptureDeviceDirty = false;
+					mRenderDeviceDirty = false;
+
+					if(!stream.str().empty())
+					{
+						writeString(stream.str());
+					}				
+
+					// This will come around again in the same state and start the capture, after the timer expires.
+					mUpdateTimer.start();
+					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+				}
+				else
 				{
 					// duration parameter is currently unused, per Mike S.
 					tuningCaptureStartSendMessage(10000);
+
+					setState(stateMicTuningRunning);
 				}
-				
-				if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty || mCaptureDeviceDirty || mRenderDeviceDirty)
+			}
+			
+		break;
+		
+		case stateMicTuningRunning:
+			if(!mTuningMode || !mVoiceEnabled || mSessionTerminateRequested || mCaptureDeviceDirty || mRenderDeviceDirty)
+			{
+				// All of these conditions make us leave tuning mode.
+				setState(stateMicTuningStop);
+			}
+			else
+			{
+				// process mic/speaker volume changes
+				if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty)
 				{
 					std::ostringstream stream;
 					
 					if(mTuningMicVolumeDirty)
 					{
+						llinfos << "setting tuning mic level to " << mTuningMicVolume << llendl;
 						stream
 						<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">"
 						<< "<Level>" << mTuningMicVolume << "</Level>"
@@ -1547,20 +1587,8 @@ void LLVoiceClient::stateMachine()
 						<< "</Request>\n\n\n";
 					}
 					
-					if(mCaptureDeviceDirty)
-					{
-						buildSetCaptureDevice(stream);
-					}
-	
-					if(mRenderDeviceDirty)
-					{
-						buildSetRenderDevice(stream);
-					}
-					
 					mTuningMicVolumeDirty = false;
 					mTuningSpeakerVolumeDirty = false;
-					mCaptureDeviceDirty = false;
-					mRenderDeviceDirty = false;
 
 					if(!stream.str().empty())
 					{
@@ -1568,23 +1596,19 @@ void LLVoiceClient::stateMachine()
 					}
 				}
 			}
-			else
-			{
-				// transition out of mic tuning
-				if(mTuningCaptureRunning)
-				{
-					tuningCaptureStopSendMessage();
-				}
-				
-				if(getState() == stateMicTuningNoLogin)
-				{
-					setState(stateConnectorStart);
-				}
-				else
-				{
-					setState(stateNoChannel);
-				}
-			}
+		break;
+		
+		case stateMicTuningStop:
+		{
+			// transition out of mic tuning
+			tuningCaptureStopSendMessage();
+			
+			setState(mTuningExitState);
+			
+			// if we exited just to change devices, this will keep us from re-entering too fast.
+			mUpdateTimer.start();
+			mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+			
 		}
 		break;
 								
@@ -1654,7 +1678,8 @@ void LLVoiceClient::stateMachine()
 			}
 			else if(mTuningMode)
 			{
-				setState(stateMicTuningLoggedIn);
+				mTuningExitState = stateNoChannel;
+				setState(stateMicTuningStart);
 			}
 			else if(!mNextSessionHandle.empty())
 			{
@@ -1880,6 +1905,12 @@ void LLVoiceClient::stateMachine()
 		case stateJail:
 			// We have given up.  Do nothing.
 		break;
+
+	        case stateMicTuningNoLogin:
+			// *TODO: Implement me.
+			llwarns << "stateMicTuningNoLogin not handled"
+				<< llendl;
+		break;
 	}
 
 	if(mParticipantMapChanged)
@@ -2183,9 +2214,9 @@ bool LLVoiceClient::inTuningMode()
 	bool result = false;
 	switch(getState())
 	{
-	case stateMicTuningNoLogin:
-	case stateMicTuningLoggedIn:
+	case stateMicTuningRunning:
 		result = true;
+		break;
 	default:
 		break;
 	}
@@ -2193,10 +2224,7 @@ bool LLVoiceClient::inTuningMode()
 }
 
 void LLVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
-{
-	if(!inTuningMode())
-		return;
-		
+{		
 	mTuningAudioFile = name;
 	std::ostringstream stream;
 	stream
@@ -2210,9 +2238,6 @@ void LLVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool l
 
 void LLVoiceClient::tuningRenderStopSendMessage()
 {
-	if(!inTuningMode())
-		return;
-
 	std::ostringstream stream;
 	stream
 	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
@@ -2224,9 +2249,8 @@ void LLVoiceClient::tuningRenderStopSendMessage()
 
 void LLVoiceClient::tuningCaptureStartSendMessage(int duration)
 {
-	if(!inTuningMode())
-		return;
-
+	llinfos << "sending CaptureAudioStart" << llendl;
+	
 	std::ostringstream stream;
 	stream
 	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
@@ -2234,15 +2258,12 @@ void LLVoiceClient::tuningCaptureStartSendMessage(int duration)
 	<< "</Request>\n\n\n";
 	
 	writeString(stream.str());
-	
-	mTuningCaptureRunning = true;
 }
 
 void LLVoiceClient::tuningCaptureStopSendMessage()
 {
-	if(!inTuningMode())
-		return;
-
+	llinfos << "sending CaptureAudioStop" << llendl;
+	
 	std::ostringstream stream;
 	stream
 	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
@@ -2250,7 +2271,7 @@ void LLVoiceClient::tuningCaptureStopSendMessage()
 	
 	writeString(stream.str());
 
-	mTuningCaptureRunning = false;
+	mTuningEnergy = 0.0f;
 }
 
 void LLVoiceClient::tuningSetMicVolume(float volume)
@@ -2914,12 +2935,16 @@ void LLVoiceClient::sessionNewEvent(
 				LLUUID caller_id;
 				if(IDFromName(nameString, caller_id))
 				{
-					gIMMgr->inviteToSession(LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, caller_id),
-											LLString::null,
-											caller_id, 
-											LLString::null, 
-											IM_SESSION_P2P_INVITE, 
-											eventSessionHandle);
+					gIMMgr->inviteToSession(
+						LLIMMgr::computeSessionID(
+							IM_SESSION_P2P_INVITE,
+							caller_id),
+						LLString::null,
+						caller_id, 
+						LLString::null, 
+						IM_SESSION_P2P_INVITE, 
+						LLIMMgr::INVITATION_TYPE_VOICE,
+						eventSessionHandle);
 				}
 				else
 				{
@@ -2985,6 +3010,7 @@ void LLVoiceClient::participantPropertiesEvent(
 	{
 		participant->mPTT = !isLocallyMuted;
 		participant->mIsSpeaking = isSpeaking;
+		participant->mIsModeratorMuted = isModeratorMuted;
 		if (isSpeaking)
 		{
 			participant->mSpeakingTimeout.reset();
@@ -3022,7 +3048,7 @@ void LLVoiceClient::muteListChanged()
 /////////////////////////////
 // Managing list of participants
 LLVoiceClient::participantState::participantState(const std::string &uri) : 
-	 mURI(uri), mPTT(false), mIsSpeaking(false), mPower(0.0), mServiceType(serviceTypeUnknown),
+	 mURI(uri), mPTT(false), mIsSpeaking(false), mIsModeratorMuted(false), mPower(0.0), mServiceType(serviceTypeUnknown),
 	 mOnMuteList(false), mUserVolume(100), mVolumeDirty(false), mAvatarIDValid(false)
 {
 }
@@ -3265,6 +3291,7 @@ void LLVoiceClient::switchChannel(
 		{
 			// Leave any channel we may be in
 			llinfos << "leaving channel" << llendl;
+			notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
 		}
 		else
 		{
@@ -3786,6 +3813,19 @@ BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
 	return result;
 }
 
+BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
+{
+	BOOL result = FALSE;
+
+	participantState *participant = findParticipantByID(id);
+	if(participant)
+	{
+		result = participant->mIsModeratorMuted;
+	}
+	
+	return result;
+}
+
 F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
 {		
 	F32 result = 0;
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index ed256b6f8c7877b1696a34695fe8411ee7a28076..5179bc099cd28f0fc8468cfac8f57f32554956d0 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -63,6 +63,7 @@ class LLVoiceClientStatusObserver
 		STATUS_JOINING,
 		STATUS_JOINED,
 		STATUS_LEFT_CHANNEL,
+		STATUS_VOICE_DISABLED,
 		BEGIN_ERROR_STATUS,
 		ERROR_CHANNEL_FULL,
 		ERROR_CHANNEL_LOCKED,
@@ -139,6 +140,7 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 		void tuningStart();
 		void tuningStop();
 		bool inTuningMode();
+		bool inTuningStates();
 		
 		void tuningRenderStartSendMessage(const std::string& name, bool loop);
 		void tuningRenderStopSendMessage();
@@ -218,6 +220,7 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 		// Accessors for data related to nearby speakers
 		BOOL getVoiceEnabled(const LLUUID& id);		// true if we've received data for this avatar
 		BOOL getIsSpeaking(const LLUUID& id);
+		BOOL getIsModeratorMuted(const LLUUID& id);
 		F32 getCurrentPower(const LLUUID& id);		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is...
 		BOOL getPTTPressed(const LLUUID& id);			// This is the inverse of the "locally muted" property.
 		BOOL getOnMuteList(const LLUUID& id);
@@ -242,6 +245,7 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 			std::string mDisplayName;
 			bool mPTT;
 			bool mIsSpeaking;
+			bool mIsModeratorMuted;
 			LLFrameTimer mSpeakingTimeout;
 			F32	mLastSpokeTimestamp;
 			F32 mPower;
@@ -316,7 +320,9 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 			stateLoggingIn,				// waiting for account handle
 			stateLoggedIn,				// account handle received
 			stateNoChannel,				// 
-			stateMicTuningLoggedIn,		// mic tuning for a logged in user
+			stateMicTuningStart,
+			stateMicTuningRunning,		
+			stateMicTuningStop,
 			stateSessionCreate,			// need to send Session.Create command
 			stateSessionConnect,		// need to send Session.Connect command
 			stateJoiningSession,		// waiting for session handle
@@ -387,7 +393,7 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 		bool mTuningMicVolumeDirty;
 		int mTuningSpeakerVolume;
 		bool mTuningSpeakerVolumeDirty;
-		bool mTuningCaptureRunning;
+		state mTuningExitState;					// state to return to when we leave tuning mode.
 		
 		std::string mSpatialSessionURI;
 		
diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp
index e6676639e2edd7036c908d2e320911774c63fcef..39f2f63066fbebe8d12d370f7c7577490dab3df0 100644
--- a/indra/newview/llvoicevisualizer.cpp
+++ b/indra/newview/llvoicevisualizer.cpp
@@ -111,7 +111,7 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type )
 	for (int i=0; i<NUM_VOICE_SYMBOL_WAVES; i++)
 	{
 		mSoundSymbol.mWaveFadeOutStartTime	[i] = mCurrentTime;
-		mSoundSymbol.mTexture				[i] = gImageList.getUIImageByID(sound_level_img[i]);
+		mSoundSymbol.mTexture				[i] = gImageList.getImageByID(sound_level_img[i]);
 		mSoundSymbol.mWaveActive			[i] = false;
 		mSoundSymbol.mWaveOpacity			[i] = 1.0f;
 		mSoundSymbol.mWaveExpansion			[i] = 1.0f;
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index dac693885f2d58cbe8257c7adfbc428190efb553..ec277b1a1b8b711be0b60cd3a4ce529e97cf990a 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1117,11 +1117,6 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
 
 BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen )
 {
-	if( !getVisible() || !pointInView( x, y ) )
-	{
-		return FALSE;
-	}
-
 	LLVector3d pos_global = viewPosToGlobal(x, y);
 
 	LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global);
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 7bb12f78535307a78975c4ba38af593e0c7c7bed..5775af68a176b8b7f0bcf80c353e119ca0fcb307 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -435,7 +435,7 @@ def package_finish(self):
                         self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
 
                 # Unmount the image
-                self.run_command('hdiutil detach "' + devfile + '"')
+                self.run_command('hdiutil detach -force "' + devfile + '"')
 
                 print "Converting temp disk image to final disk image"
                 self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index c7ce013dcdbc4ee10115d1aa15b311fddd411d84..5332b1263dfb4c64f6434efe6cf7b5154f3c27c0 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -8178,7 +8178,7 @@ version 2.0
 // dataserver -> userserver
 // reliable
 {
-	AgentDropGroup Low 390 Trusted Zerocoded
+	AgentDropGroup Low 390 Trusted Zerocoded UDPDeprecated
 	{
 		AgentData			Single
 		{	AgentID				LLUUID	}