From 2b863df7c8fdede8db5d30349f7778d9f7897e28 Mon Sep 17 00:00:00 2001
From: James Cook <james@lindenlab.com>
Date: Tue, 20 May 2008 23:24:16 +0000
Subject: [PATCH] svn merge -r87877:87878
 svn+ssh://svn.lindenlab.com/svn/linden/branches/maint-ui/maint-ui-12-qa-5
 which is the last iteration of the maint-ui series of branches.  Future work
 will be in featurettes.

---
 indra/llui/llmenugl.cpp          | 37 ++++++++++++++--
 indra/llui/llmenugl.h            |  4 +-
 indra/newview/llchatbar.cpp      |  1 +
 indra/newview/llimpanel.cpp      | 48 ++++++++++++++++++---
 indra/newview/llpanelplace.h     |  2 +
 indra/newview/lltexturectrl.cpp  | 26 +++++++++++-
 indra/newview/lltexturectrl.h    |  4 ++
 indra/newview/llvoavatar.cpp     | 73 +++++++++++++++++++++++---------
 indra/newview/llvoavatar.h       | 14 +++++-
 indra/newview/llworldmapview.cpp | 22 +++++++++-
 indra/newview/llworldmapview.h   |  2 +
 11 files changed, 200 insertions(+), 33 deletions(-)

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 8ae44fbfd52..bc4445ea6cb 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3879,6 +3879,8 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
 		}
 		else
 		{
+			// close menus originating from other menu bars when first opening menu via keyboard
+			LLMenuGL::sMenuContainer->hideMenus();
 			highlightNextItem(NULL);
 			LLMenuGL::setKeyboardMode(TRUE);
 		}
@@ -3921,13 +3923,38 @@ BOOL LLMenuBarGL::handleJumpKey(KEY key)
 	return TRUE;
 }
 
+BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	// clicks on menu bar closes existing menus from other contexts but leave
+	// own menu open so that we get toggle behavior
+	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
+	{
+		LLMenuGL::sMenuContainer->hideMenus();
+	}
+
+	return LLMenuGL::handleMouseDown(x, y, mask);
+}
+
+BOOL LLMenuBarGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+	// clicks on menu bar closes existing menus from other contexts but leave
+	// own menu open so that we get toggle behavior
+	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
+	{
+		LLMenuGL::sMenuContainer->hideMenus();
+	}
+
+	return LLMenuGL::handleMouseDown(x, y, mask);
+}
+
+
 void LLMenuBarGL::draw()
 {
 	LLMenuItemGL* itemp = getHighlightedItem();
 	// If we are in mouse-control mode and the mouse cursor is not hovering over
-	// the current highlighted menu item and it isn't open, then remove the highlight.
-	// This is done via a polling mechanism here, as we don't receive notifications when
-	// the mouse cursor moves off of us
+	// the current highlighted menu item and it isn't open, then remove the
+	// highlight. This is done via a polling mechanism here, as we don't receive
+    // notifications when the mouse cursor moves off of us
 	if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode())
 	{
 		clearHoverItem();
@@ -3954,6 +3981,9 @@ void LLMenuBarGL::checkMenuTrigger()
 			}
 			else
 			{
+				// close menus originating from other menu bars
+				LLMenuGL::sMenuContainer->hideMenus();
+
 				highlightNextItem(NULL);
 				LLMenuGL::setKeyboardMode(TRUE);
 			}
@@ -4362,6 +4392,7 @@ LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
 	// keep onscreen
 	gFloaterView->adjustToFitScreen(tearoffp, FALSE);
 	tearoffp->open();	/* Flawfinder: ignore */
+
 	return tearoffp;
 }
 
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 77998be880a..16ab61c6071 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -499,7 +499,7 @@ class LLMenuGL
 	void setDropShadowed( const BOOL shadowed );
 
 	void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item; }
-	LLMenuItemGL* getParentMenuItem() { return mParentMenuItem; }
+	LLMenuItemGL* getParentMenuItem() const { return mParentMenuItem; }
 
 	void setTornOff(BOOL torn_off);
 	BOOL getTornOff() { return mTornOff; }
@@ -690,6 +690,8 @@ class LLMenuBarGL : public LLMenuGL
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 	virtual BOOL handleJumpKey(KEY key);
+	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
 
 	// rearrange the child rects so they fit the shape of the menu
 	// bar.
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 59553922ed1..e2ab30f1cb5 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -382,6 +382,7 @@ void LLChatBar::sendChat( EChatType type )
 	LLWString text;
 	if (mInputEditor) text = mInputEditor->getWText();
 	LLWString::trim(text);
+	LLWString::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
 
 	if (!text.empty())
 	{
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index ba43352eb5a..e58db2988f1 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -1601,12 +1601,48 @@ BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 	BOOL accepted = FALSE;
 	switch(cargo_type)
 	{
-	case DAD_CALLINGCARD:
-		accepted = dropCallingCard((LLInventoryItem*)cargo_data, drop);
-		break;
-	case DAD_CATEGORY:
-		accepted = dropCategory((LLInventoryCategory*)cargo_data, drop);
-		break;
+		case DAD_CALLINGCARD:
+		{
+			accepted = dropCallingCard((LLInventoryItem*)cargo_data, drop);
+			break;
+		}
+		case DAD_CATEGORY:
+		{
+			accepted = dropCategory((LLInventoryCategory*)cargo_data, drop);
+			break;
+		}
+
+		// See stdenums.h
+		case DAD_TEXTURE:
+		case DAD_SOUND:
+		// DAD_CALLINGCARD above
+		case DAD_LANDMARK:
+		case DAD_SCRIPT:
+		case DAD_CLOTHING:
+		case DAD_OBJECT:
+		case DAD_NOTECARD:
+		// DAD_CATEGORY above
+		case DAD_BODYPART:
+		case DAD_ANIMATION:
+		case DAD_GESTURE:
+		{
+			if (mDialog == IM_NOTHING_SPECIAL)
+			{
+				// See LLDropTarget for similar code.
+				LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
+				if(gInventory.getItem(inv_item->getUUID())
+				   && LLToolDragAndDrop::isInventoryGiveAcceptable(inv_item))
+				{
+					accepted = true;
+					if(drop)
+					{
+						LLToolDragAndDrop::giveInventory(mOtherParticipantUUID, inv_item);
+					}
+				}
+			}
+			break;
+		}
+		
 	default:
 		break;
 	}
diff --git a/indra/newview/llpanelplace.h b/indra/newview/llpanelplace.h
index c4739006931..7a09f5cca61 100644
--- a/indra/newview/llpanelplace.h
+++ b/indra/newview/llpanelplace.h
@@ -74,6 +74,8 @@ class LLPanelPlace : public LLPanel
 			const LLVector3d& pos_global);
 	static void processParcelInfoReply(LLMessageSystem* msg, void**);
 
+	LLTextureCtrl *getSnapshotCtrl() const { return mSnapshotCtrl; }
+
 protected:
 	static void onClickTeleport(void* data);
 	static void onClickMap(void* data);
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 6625e10982a..22c0e086122 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -65,6 +65,7 @@
 #include "llviewercontrol.h"
 #include "llglheaders.h"
 #include "lluictrlfactory.h"
+#include "lltrans.h"
 
 
 static const S32 CLOSE_BTN_WIDTH = 100;
@@ -908,7 +909,8 @@ LLTextureCtrl::LLTextureCtrl(
 	mCanApplyImmediately( FALSE ),
 	mNeedsRawImageData( FALSE ),
 	mValid( TRUE ),
-	mDirty( FALSE )
+	mDirty( FALSE ),
+	mShowLoadingPlaceholder( FALSE )
 {
 	mCaption = new LLTextBox( label, 
 		LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ),
@@ -939,6 +941,7 @@ LLTextureCtrl::LLTextureCtrl(
 	addChild(mBorder);
 
 	setEnabled(TRUE); // for the tooltip
+	mLoadingPlaceholderString = LLTrans::getString("texture_loading");
 }
 
 
@@ -1009,6 +1012,11 @@ LLView* LLTextureCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
 	return texture_picker;
 }
 
+void LLTextureCtrl::setShowLoadingPlaceholder(BOOL showLoadingPlaceholder)
+{
+	mShowLoadingPlaceholder = showLoadingPlaceholder;
+}
+
 void LLTextureCtrl::setCaption(const LLString& caption)
 {
 	mCaption->setText( caption );
@@ -1318,6 +1326,22 @@ void LLTextureCtrl::draw()
 	}
 
 	mTentativeLabel->setVisible( !mTexturep.isNull() && getTentative() );
+	
+	if ( mTexturep.notNull() &&
+		 (mShowLoadingPlaceholder == TRUE) && 
+		 (mTexturep->getDiscardLevel() != 1) &&
+		 (mTexturep->getDiscardLevel() != 0))
+	{
+		LLFontGL* font = LLFontGL::sSansSerifBig;
+		font->renderUTF8(
+			mLoadingPlaceholderString, 0,
+			llfloor(interior.mLeft+10), 
+			llfloor(interior.mTop-20),
+			LLColor4::white,
+			LLFontGL::LEFT,
+			LLFontGL::BASELINE,
+			LLFontGL::DROP_SHADOW);
+	}
 
 	LLUICtrl::draw();
 }
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index dbdade3b78b..5dabf07ce5c 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -147,6 +147,8 @@ class LLTextureCtrl
 	
 	void setOnSelectCallback(LLUICtrlCallback cb)	{ mOnSelectCallback = cb; }
 
+	void setShowLoadingPlaceholder(BOOL showLoadingPlaceholder);
+
 private:
 	BOOL allowDrop(LLInventoryItem* item);
 	BOOL doDrop(LLInventoryItem* item);
@@ -175,6 +177,8 @@ class LLTextureCtrl
 	LLViewBorder*			 mBorder;
 	BOOL					 mValid;
 	BOOL					 mDirty;
+	BOOL					 mShowLoadingPlaceholder;
+	LLString				 mLoadingPlaceholderString;
 };
 
 // XUI HACK: When floaters converted, switch this file to lltexturepicker.h/cpp
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index d7dfd8ac4a8..8762c4fef85 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -2465,12 +2465,32 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	// animate the character
 	// store off last frame's root position to be consistent with camera position
 	LLVector3 root_pos_last = mRoot.getWorldPosition();
-	BOOL detailed_update = updateCharacter(agent);
-	bool voiceEnabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel();
+	bool detailed_update = updateCharacter(agent);
+	bool voice_enabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel();
 
+	if (gNoRender)
+	{
+		return TRUE;
+	}
+
+	idleUpdateVoiceVisualizer( voice_enabled );
+	idleUpdateMisc( detailed_update );
+	idleUpdateAppearanceAnimation();
+	idleUpdateLipSync( voice_enabled );
+	idleUpdateLoadingEffect();
+	idleUpdateBelowWater();	// wind effect uses this
+	idleUpdateWindEffect();
+	idleUpdateNameTag( root_pos_last );
+	idleUpdateRenderCost();
+	idleUpdateTractorBeam();
+	return TRUE;
+}
+
+void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
+{
 	// disable voice visualizer when in mouselook
-	mVoiceVisualizer->setVoiceEnabled( voiceEnabled && !(mIsSelf && gAgent.cameraMouselook()) );
-	if ( voiceEnabled )
+	mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(mIsSelf && gAgent.cameraMouselook()) );
+	if ( voice_enabled )
 	{		
 		//----------------------------------------------------------------
 		// Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
@@ -2552,7 +2572,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
 		
 	}//if ( voiceEnabled )
-		
+}		
+
+void LLVOAvatar::idleUpdateMisc(bool detailed_update)
+{
 	if (LLVOAvatar::sJointDebug)
 	{
 		llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl;
@@ -2561,11 +2584,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	LLJoint::sNumUpdates = 0;
 	LLJoint::sNumTouches = 0;
 
-	if (gNoRender)
-	{
-		return TRUE;
-	}
-
 	// *NOTE: this is necessary for the floating name text above your head.
 	if (mDrawable.notNull())
 	{
@@ -2661,7 +2679,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	{
 		gPipeline.markMoved(mDrawable, TRUE);
 	}
+}
 
+void LLVOAvatar::idleUpdateAppearanceAnimation()
+{
 	// update morphing params
 	if (mAppearanceAnimating)
 	{
@@ -2724,9 +2745,12 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		}
 		dirtyMesh();
 	}
+}
 
+void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
+{
 	// Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
-	if ( voiceEnabled && (gVoiceClient->lipSyncEnabled() > 0) && gVoiceClient->getIsSpeaking( mID ) )
+	if ( voice_enabled && (gVoiceClient->lipSyncEnabled() > 0) && gVoiceClient->getIsSpeaking( mID ) )
 	{
 		F32 ooh_morph_amount = 0.0f;
 		F32 aah_morph_amount = 0.0f;
@@ -2753,7 +2777,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		LLCharacter::updateVisualParams();
 		dirtyMesh();
 	}
+}
 
+void LLVOAvatar::idleUpdateLoadingEffect()
+{
 	// update visibility when avatar is partially loaded
 	if (updateIsFullyLoaded()) // changed?
 	{
@@ -2793,8 +2820,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 			setParticleSource(particle_parameters, getID());
 		}
 	}
-	
+}	
 
+void LLVOAvatar::idleUpdateWindEffect()
+{
 	// update wind effect
 	if ((LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH))
 	{
@@ -2849,7 +2878,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 			mRipplePhase = fmodf(mRipplePhase, F_TWO_PI);
 		}
 	}
+}
 
+void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
+{
 	// update chat bubble
 	//--------------------------------------------------------------------
 	// draw text label over characters head
@@ -2862,9 +2894,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	const F32 time_visible = mTimeVisible.getElapsedTimeF32();
 	const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime");	// seconds
 	const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
+	BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
 	BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
 	BOOL render_name =	visible_chat ||
-						(visible &&
+						(visible_avatar &&
 						((sRenderName == RENDER_NAME_ALWAYS) ||
 						(sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
 	// If it's your own avatar, don't draw in mouselook, and don't
@@ -3159,15 +3192,16 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		mNameText = NULL;
 		sNumVisibleChatBubbles--;
 	}
+}
 
-	shame();
-
+void LLVOAvatar::idleUpdateTractorBeam()
+{
 	//--------------------------------------------------------------------
 	// draw tractor beam when editing objects
 	//--------------------------------------------------------------------
 	if (!mIsSelf)
 	{
-		return TRUE;
+		return;
 	}
 
 	// This is only done for yourself (maybe it should be in the agent?)
@@ -3228,15 +3262,16 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 			mBeamTimer.reset();
 		}
 	}
+}
 
+void LLVOAvatar::idleUpdateBelowWater()
+{
 	F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]);
 
 	F32 water_height;
 	water_height = getRegion()->getWaterHeight();
 
 	mBelowWater =  avatar_height < water_height;
-	
-	return TRUE;
 }
 
 void LLVOAvatar::slamPosition()
@@ -9853,7 +9888,7 @@ U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures)
 	return shame;
 }
 
-void LLVOAvatar::shame()
+void LLVOAvatar::idleUpdateRenderCost()
 {
 	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
 	{
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 0d495311e7a..d958c40eb2d 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -283,7 +283,18 @@ class LLVOAvatar :
 										U32 block_num,
 										const EObjectUpdateType update_type,
 										LLDataPacker *dp);
-	virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+	/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+	void idleUpdateVoiceVisualizer(bool voice_enabled);
+	void idleUpdateMisc(bool detailed_update);
+	void idleUpdateAppearanceAnimation();
+	void idleUpdateLipSync(bool voice_enabled);
+	void idleUpdateLoadingEffect();
+	void idleUpdateWindEffect();
+	void idleUpdateNameTag(const LLVector3& root_pos_last);
+	void idleUpdateRenderCost();
+	void idleUpdateTractorBeam();
+	void idleUpdateBelowWater();
+
 	virtual BOOL updateLOD();
 	void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; }
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
@@ -1008,7 +1019,6 @@ class LLVOAvatar :
 	LLHost			getObjectHost() const;
 	S32				getLocalDiscardLevel( S32 index);
 	
-	void			shame();  //generate shame metric
 //Ventrella
 	//-----------------------------------------------------------------------------------------------
 	// the Voice Visualizer is responsible for detecting the user's voice signal, and when the
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index b48299623cf..1db9e5db30c 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -61,6 +61,7 @@
 #include "llviewerwindow.h"
 #include "llworldmap.h"
 #include "llappviewer.h"				// Only for constants!
+#include "lltrans.h"
 
 #include "llglheaders.h"
 
@@ -98,6 +99,7 @@ S32 LLWorldMapView::sTrackingArrowY = 0;
 F32 LLWorldMapView::sPixelsPerMeter = 1.f;
 F32 CONE_SIZE = 0.6f;
 
+std::map<std::string,LLString> LLWorldMapView::sStringsMap;
 
 #define SIM_NULL_MAP_SCALE 1 // width in pixels, where we start drawing "null" sims
 #define SIM_MAP_AGENT_SCALE 2 // width in pixels, where we start drawing agents
@@ -126,6 +128,9 @@ void LLWorldMapView::initClass()
 	sTrackArrowImage =		LLUI::getUIImage("direction_arrow.tga");
 	sClassifiedsImage =		LLUI::getUIImage("icon_top_pick.tga");
 	sForSaleImage =			LLUI::getUIImage("icon_for_sale.tga");
+	
+	sStringsMap["loading"] = LLTrans::getString("texture_loading");
+	sStringsMap["offline"] = LLTrans::getString("worldmap_offline");
 }
 
 // static
@@ -638,7 +643,7 @@ void LLWorldMapView::draw()
 			//			LLViewerRegion::accessToShortString(info->mAccess) );
 			if (info->mAccess == SIM_ACCESS_DOWN)
 			{
-				snprintf(mesg, MAX_STRING, "%s (Offline)", info->mName.c_str());		/* Flawfinder: ignore */
+				snprintf(mesg, MAX_STRING, "%s (%s)", info->mName.c_str(), sStringsMap["offline"].c_str());		/* Flawfinder: ignore */
 			}
 			else
 			{
@@ -656,6 +661,21 @@ void LLWorldMapView::draw()
 				LLFontGL::LEFT,
 				LLFontGL::BASELINE,
 				LLFontGL::DROP_SHADOW);
+			
+			// If map texture is still loading,
+			// display "Loading" placeholder text.
+			if (simimage->getDiscardLevel() != 1 &&
+				simimage->getDiscardLevel() != 0)
+			{
+				font->renderUTF8(
+					sStringsMap["loading"].c_str(), 0,
+					llfloor(left + 18), 
+					llfloor(top - 25),
+					LLColor4::white,
+					LLFontGL::LEFT,
+					LLFontGL::BASELINE,
+					LLFontGL::DROP_SHADOW);			
+			}
 		}
 	}
 #endif
diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h
index 9bad5a8a678..8f70b79f2eb 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -187,6 +187,8 @@ class LLWorldMapView : public LLPanel
 
 	typedef std::vector<U64> handle_list_t;
 	handle_list_t mVisibleRegions; // set every frame
+
+	static std::map<std::string,LLString> sStringsMap;
 };
 
 #endif
-- 
GitLab