From 406195e4f20e0bea341c8a7a979b56a8259b8536 Mon Sep 17 00:00:00 2001
From: Leslie Linden <none@none>
Date: Tue, 24 May 2011 09:38:49 -0700
Subject: [PATCH] Added badges version 0.1 to buttons.

Reviewed by Richard
---
 indra/llcommon/lldate.h                       |   2 +
 indra/llui/CMakeLists.txt                     |   2 +
 indra/llui/llbadge.cpp                        | 263 ++++++++++++++++++
 indra/llui/llbadge.h                          | 152 ++++++++++
 indra/llui/llbutton.cpp                       |  94 ++++++-
 indra/llui/llbutton.h                         |  12 +-
 indra/llxuixml/llinitparam.h                  |   2 +
 indra/newview/skins/default/colors.xml        |   6 +
 .../skins/default/textures/textures.xml       |   2 +
 .../skins/default/textures/widgets/Badge.png  | Bin 0 -> 1716 bytes
 .../skins/default/xui/en/widgets/badge.xml    |  14 +
 11 files changed, 543 insertions(+), 6 deletions(-)
 create mode 100644 indra/llui/llbadge.cpp
 create mode 100644 indra/llui/llbadge.h
 create mode 100644 indra/newview/skins/default/textures/widgets/Badge.png
 create mode 100644 indra/newview/skins/default/xui/en/widgets/badge.xml

diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 7ff8b550adf..f2bf2366acf 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -34,6 +34,8 @@
 
 #include "stdtypes.h"
 
+#include "llpreprocessor.h"
+
 /** 
  * @class LLDate
  * @brief This class represents a particular point in time in UTC.
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 33ab2e93b5c..fb585e062c8 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -28,6 +28,7 @@ include_directories(
 set(llui_SOURCE_FILES
     llaccordionctrl.cpp
     llaccordionctrltab.cpp
+    llbadge.cpp
     llbutton.cpp
     llcheckboxctrl.cpp
     llclipboard.cpp
@@ -119,6 +120,7 @@ set(llui_HEADER_FILES
 
     llaccordionctrl.h
     llaccordionctrltab.h
+    llbadge.h
     llbutton.h
     llcallbackmap.h
     llcheckboxctrl.h
diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp
new file mode 100644
index 00000000000..ea934aa93ba
--- /dev/null
+++ b/indra/llui/llbadge.cpp
@@ -0,0 +1,263 @@
+/** 
+ * @file llbadge.cpp
+ * @brief Implementation for badges
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#define LLBADGE_CPP
+#include "llbadge.h"
+
+#include "lluictrlfactory.h"
+
+
+static LLDefaultChildRegistry::Register<LLBadge> r("badge");
+
+// Compiler optimization, generate extern template
+template class LLBadge* LLView::getChild<class LLBadge>(const std::string& name, BOOL recurse) const;
+
+
+LLBadge::Params::Params()
+	: image("image")
+	, image_color("image_color")
+	, label("label")
+	, label_color("label_color")
+	, location("location", LLRelPos::TOP_LEFT)
+	, location_percent_hcenter("location_percent_hcenter")
+	, location_percent_vcenter("location_percent_vcenter")
+	, padding_horiz("padding_horiz")
+	, padding_vert("padding_vert")
+{
+	// We set a name here so the name isn't necessary in any xml files that use badges
+	name = "badge";
+}
+
+bool LLBadge::Params::equals(const Params& a) const
+{
+	bool comp = true;
+	
+	// skip owner in comparison on purpose
+	
+	comp &= (image() == a.image());
+	comp &= (image_color() == a.image_color());
+	comp &= (label() == a.label());
+	comp &= (label_color() == a.label_color());
+	comp &= (location() == a.location());
+	comp &= (location_percent_hcenter() == a.location_percent_hcenter());
+	comp &= (location_percent_vcenter() == a.location_percent_vcenter());
+	comp &= (padding_horiz() == a.padding_horiz());
+	comp &= (padding_vert() == a.padding_vert());
+	
+	return comp;
+}
+
+LLBadge::LLBadge(const LLBadge::Params& p)
+	: LLUICtrl(p)
+	, mOwner(p.owner)
+	, mGLFont(p.font)
+	, mImage(p.image)
+	, mImageColor(p.image_color)
+	, mLabel(p.label)
+	, mLabelColor(p.label_color)
+	, mLocation(p.location)
+	, mLocationPercentHCenter(0.5f)
+	, mLocationPercentVCenter(0.5f)
+	, mPaddingHoriz(p.padding_horiz)
+	, mPaddingVert(p.padding_vert)
+{
+	if (mImage.isNull())
+	{
+		llwarns << "Badge: " << getName() << " with no image!" << llendl;
+	}
+
+	//
+	// The following logic is to set the mLocationPercentHCenter and mLocationPercentVCenter
+	// based on the Location enum and our horizontal and vertical location percentages.  The
+	// draw code then uses this on the owner rectangle to compute the screen location for
+	// the badge.
+	//
+
+	if (!LLRelPos::IsCenter(mLocation))
+	{
+		F32 h_center = p.location_percent_hcenter * 0.01f;
+		F32 v_center = p.location_percent_vcenter * 0.01f;
+
+		if (LLRelPos::IsRight(mLocation))
+		{
+			mLocationPercentHCenter = 0.5f * (1.0f + h_center);
+		}
+		else if (LLRelPos::IsLeft(mLocation))
+		{
+			mLocationPercentHCenter = 0.5f * (1.0f - h_center);
+		}
+			
+		if (LLRelPos::IsTop(mLocation))
+		{
+			mLocationPercentVCenter = 0.5f * (1.0f + v_center);
+		}
+		else if (LLRelPos::IsBottom(mLocation))
+		{
+			mLocationPercentVCenter = 0.5f * (1.0f - v_center);
+		}
+	}
+}
+
+LLBadge::~LLBadge()
+{
+}
+
+void LLBadge::setLabel(const LLStringExplicit& label)
+{
+	mLabel = label;
+}
+
+//
+// This is a fallback function to render a rectangle for badges without a valid image
+//
+void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, const LLColor4U &color)
+{
+	gGL.pushUIMatrix();
+	gGL.loadUIIdentity();
+	gGL.setSceneBlendType(LLRender::BT_REPLACE);
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	
+	gGL.color4ubv(color.mV);
+	gGL.texCoord2i(0, 0);
+	
+	F32 x = LLFontGL::sCurOrigin.mX + centerX - width * 0.5f;
+	F32 y = LLFontGL::sCurOrigin.mY + centerY - height * 0.5f;
+	
+	LLRectf screen_rect(llround(x),
+						llround(y),
+						llround(x) + width,
+						llround(y) + height);
+	
+	LLVector3 vertices[4];
+	vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop,    1.0f);
+	vertices[1] = LLVector3(screen_rect.mLeft,  screen_rect.mTop,    1.0f);
+	vertices[2] = LLVector3(screen_rect.mLeft,  screen_rect.mBottom, 1.0f);
+	vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f);
+	
+	gGL.begin(LLRender::QUADS);
+	{
+		gGL.vertexBatchPreTransformed(vertices, 4);
+	}
+	gGL.end();
+	
+	gGL.popUIMatrix();
+}
+
+
+// virtual
+void LLBadge::draw()
+{
+	if (!mLabel.empty())
+	{
+		LLUICtrl* owner_ctrl = mOwner.get();
+
+		if (owner_ctrl)
+		{
+			//
+			// Calculate badge position based on owner
+			//
+			
+			LLRect owner_rect;
+			owner_ctrl->localRectToOtherView(owner_ctrl->getLocalRect(), & owner_rect, this);
+			
+			F32 badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter;
+			F32 badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter;
+
+			//
+			// Calculate badge size based on label text
+			//
+
+			LLWString badge_label_wstring = mLabel;
+			
+			S32 badge_label_begin_offset = 0;
+			S32 badge_char_length = S32_MAX;
+			S32 badge_pixel_length = S32_MAX;
+			F32 *right_position_out = NULL;
+			BOOL do_not_use_ellipses = false;
+
+			F32 badge_width = (2.0f * mPaddingHoriz) +
+				mGLFont->getWidthF32(badge_label_wstring.c_str(), badge_label_begin_offset, badge_char_length);
+
+			F32 badge_height = (2.0f * mPaddingVert) + mGLFont->getLineHeight();
+
+			//
+			// Draw button image, if available.
+			// Otherwise draw basic rectangular button.
+			//
+
+			F32 alpha = getDrawContext().mAlpha;
+
+			if (!mImage.isNull())
+			{
+				F32 badge_x = badge_center_x - badge_width * 0.5f;
+				F32 badge_y = badge_center_y - badge_height * 0.5f;
+			
+				mImage->drawSolid(badge_x, badge_y, badge_width, badge_height, mImageColor % alpha);
+			}
+			else
+			{
+				lldebugs << "No image for badge " << getName() << " on owner " << owner_ctrl->getName() << llendl;
+				
+				renderBadgeBackground(badge_center_x, badge_center_y,
+									  badge_width, badge_height,
+									  mImageColor % alpha);
+			}
+
+			//
+			// Draw the label
+			//
+
+			mGLFont->render(badge_label_wstring, badge_label_begin_offset,
+							badge_center_x, badge_center_y,
+							mLabelColor % alpha,
+							LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
+							LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
+							LLFontGL::DROP_SHADOW_SOFT,
+							badge_char_length, badge_pixel_length,
+							right_position_out, do_not_use_ellipses);
+		}
+	}
+}
+
+
+namespace LLInitParam
+{
+	void TypeValues<LLRelPos::Location>::declareValues()
+	{
+		declare("bottom",		LLRelPos::BOTTOM);
+		declare("bottom_left",	LLRelPos::BOTTOM_LEFT);
+		declare("bottom_right", LLRelPos::BOTTOM_RIGHT);
+		declare("center",		LLRelPos::CENTER);
+		declare("left",			LLRelPos::LEFT);
+		declare("right",		LLRelPos::RIGHT);
+		declare("top",			LLRelPos::TOP);
+		declare("top_left",		LLRelPos::TOP_LEFT);
+		declare("top_right",	LLRelPos::TOP_RIGHT);
+	}
+}
+
+
+// eof
diff --git a/indra/llui/llbadge.h b/indra/llui/llbadge.h
new file mode 100644
index 00000000000..c2e0a763b2d
--- /dev/null
+++ b/indra/llui/llbadge.h
@@ -0,0 +1,152 @@
+/** 
+ * @file llbadge.h
+ * @brief Header for badges
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLBADGE_H
+#define LL_LLBADGE_H
+
+#include <string>
+
+#include "lluicolor.h"
+#include "lluictrl.h"
+#include "llstring.h"
+#include "lluiimage.h"
+
+//
+// Declarations
+//
+
+class LLUICtrlFactory;
+class LLFontGL;
+
+//
+// Relative Position Alignment
+//
+
+namespace LLRelPos
+{
+	enum Location
+	{
+		CENTER	= 0,
+
+		LEFT	= (1 << 0),
+		RIGHT	= (1 << 1),
+
+		TOP		= (1 << 2),
+		BOTTOM	= (1 << 3),
+
+		BOTTOM_LEFT		= (BOTTOM | LEFT),
+		BOTTOM_RIGHT	= (BOTTOM | RIGHT),
+
+		TOP_LEFT		= (TOP | LEFT),
+		TOP_RIGHT		= (TOP | RIGHT),
+	};
+
+	inline bool IsBottom(Location relPos)	{ return (relPos & BOTTOM) == BOTTOM; }
+	inline bool IsCenter(Location relPos)	{ return (relPos == CENTER); }
+	inline bool IsLeft(Location relPos)		{ return (relPos & LEFT) == LEFT; }
+	inline bool IsRight(Location relPos)	{ return (relPos & RIGHT) == RIGHT; }
+	inline bool IsTop(Location relPos)		{ return (relPos & TOP) == TOP; }
+}
+
+// NOTE: This needs to occur before Optional<LLRelPos::Location> declaration for proper compilation.
+namespace LLInitParam
+{
+	template<>
+	struct TypeValues<LLRelPos::Location> : public TypeValuesHelper<LLRelPos::Location>
+	{
+		static void declareValues();
+	};
+}
+
+//
+// Classes
+//
+
+class LLBadge
+: public LLUICtrl
+{
+public:
+	struct Params 
+	: public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional< LLHandle<LLUICtrl> >	owner;	// Mandatory in code but not in xml
+		
+		Optional< LLUIImage* >			image;
+		Optional< LLUIColor >			image_color;
+		
+		Optional< std::string >			label;
+		Optional< LLUIColor >			label_color;
+
+		Optional< LLRelPos::Location >	location;
+		Optional< U32 >					location_percent_hcenter;
+		Optional< U32 >					location_percent_vcenter;
+
+		Optional< F32 >					padding_horiz;
+		Optional< F32 >					padding_vert;
+		
+		Params();
+		
+		bool equals(const Params&) const;
+	};
+	
+protected:
+	friend class LLUICtrlFactory;
+	LLBadge(const Params& p);
+
+public:
+
+	~LLBadge();
+	
+	virtual void		draw();
+
+	const std::string	getLabel() const { return wstring_to_utf8str(mLabel); }
+	void				setLabel( const LLStringExplicit& label);
+
+private:
+	const LLFontGL*			mGLFont;
+	
+	LLPointer< LLUIImage >	mImage;
+	LLUIColor				mImageColor;
+	
+	LLUIString				mLabel;
+	LLUIColor				mLabelColor;
+
+	LLRelPos::Location		mLocation;
+	F32						mLocationPercentHCenter;
+	F32						mLocationPercentVCenter;
+	
+	LLHandle< LLUICtrl >	mOwner;
+
+	F32						mPaddingHoriz;
+	F32						mPaddingVert;
+};
+
+// Build time optimization, generate once in .cpp file
+#ifndef LLBADGE_CPP
+extern template class LLBadge* LLView::getChild<class LLBadge>(const std::string& name, BOOL recurse) const;
+#endif
+
+#endif  // LL_LLBADGE_H
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 45ceaff6969..a63281b3c12 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -56,6 +56,9 @@ static LLDefaultChildRegistry::Register<LLButton> r("button");
 template class LLButton* LLView::getChild<class LLButton>(
 	const std::string& name, BOOL recurse) const;
 
+
+
+
 // globals loaded from settings.xml
 S32	LLBUTTON_H_PAD	= 0;
 S32 BTN_HEIGHT_SMALL= 0;
@@ -99,7 +102,8 @@ LLButton::Params::Params()
 	scale_image("scale_image", true),
 	hover_glow_amount("hover_glow_amount"),
 	commit_on_return("commit_on_return", true),
-	use_draw_context_alpha("use_draw_context_alpha", true)
+	use_draw_context_alpha("use_draw_context_alpha", true),
+	badge("badge")
 {
 	addSynonym(is_toggle, "toggle");
 	held_down_delay.seconds = 0.5f;
@@ -160,8 +164,8 @@ LLButton::LLButton(const LLButton::Params& p)
 	mMouseDownSignal(NULL),
 	mMouseUpSignal(NULL),
 	mHeldDownSignal(NULL),
-	mUseDrawContextAlpha(p.use_draw_context_alpha)
-
+	mUseDrawContextAlpha(p.use_draw_context_alpha),
+	mBadge(NULL)
 {
 	static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
 	static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
@@ -244,6 +248,17 @@ LLButton::LLButton(const LLButton::Params& p)
 	{
 		setHeldDownCallback(initCommitCallback(p.mouse_held_callback));
 	}
+	
+	// Only create a badge here if a non-default one was provided.
+	if (p.badge.isProvided())
+	{
+		if (!p.badge().equals(LLUICtrlFactory::getDefaultParams<LLBadge>()))
+		{
+			LLBadge::Params badge_params(p.badge());
+			badge_params.owner = getUICtrlHandle();
+			mBadge = LLUICtrlFactory::create<LLBadge>(badge_params);
+		}
+	}
 }
 
 LLButton::~LLButton()
@@ -327,6 +342,13 @@ boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb,
 BOOL LLButton::postBuild()
 {
 	autoResize();
+
+	// Attach the badge to the appropriate parent panel
+	if (mBadge)
+	{
+		addBadgeToParentPanel();
+	}
+
 	return TRUE;
 }
 BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
@@ -867,7 +889,7 @@ void LLButton::draw()
 			S32_MAX, text_width,
 			NULL, mUseEllipses);
 	}
-
+	
 	LLUICtrl::draw();
 }
 
@@ -1063,6 +1085,70 @@ void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignmen
 	}
 }
 
+void LLButton::addBadgeToParentPanel()
+{
+	if (mBadge)
+	{
+		// Find the appropriate parent panel for the badge
+
+		LLPanel * parentPanel = NULL;
+		LLUICtrl * parent = getParentUICtrl();
+		
+		while (parent)
+		{
+			parentPanel = dynamic_cast<LLPanel*>(parent);
+		
+			if (parentPanel != NULL)
+			{
+				break;
+			}
+
+			parent = parent->getParentUICtrl();
+		}
+
+		if (parentPanel)
+		{
+			parentPanel->addChild(mBadge);
+		}
+		else
+		{
+			llwarns << "Unable to find parent panel for badge " << mBadge->getName() << " on button " << getName() << llendl;
+		}
+	}
+	else
+	{
+		llwarns << "Unable to add NULL badge to button " << getName() << llendl;
+	}
+}
+
+void LLButton::setBadgeLabel(const LLStringExplicit& label)
+{
+	if (mBadge == NULL)
+	{
+		LLBadge::Params badge_params(LLUICtrlFactory::getDefaultParams<LLBadge>());
+		badge_params.owner = getUICtrlHandle();
+		mBadge = LLUICtrlFactory::create<LLBadge>(badge_params);
+
+		addBadgeToParentPanel();
+	}
+
+	if (mBadge)
+	{
+		mBadge->setLabel(label);
+
+		//
+		// Push the badge to the front so it renders last
+		//
+
+		LLUICtrl * parent = mBadge->getParentUICtrl();
+
+		if (parent)
+		{
+			parent->sendChildToFront(mBadge);
+		}
+	}
+}
+
 void LLButton::onMouseCaptureLost()
 {
 	resetMouseDownTimer();
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 0cfc393e050..232ab81e0d3 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -27,6 +27,8 @@
 #ifndef LL_LLBUTTON_H
 #define LL_LLBUTTON_H
 
+#include "lluuid.h"
+#include "llbadge.h"
 #include "llcontrol.h"
 #include "lluictrl.h"
 #include "v4color.h"
@@ -52,8 +54,6 @@ S32 round_up(S32 grid, S32 value);
 
 
 class LLUICtrlFactory;
-class LLUIImage;
-class LLUUID;
 
 //
 // Classes
@@ -126,6 +126,8 @@ class LLButton
 		Optional<TimeIntervalParam>	held_down_delay;
 
 		Optional<bool>			use_draw_context_alpha;
+		
+		Optional<LLBadge::Params>	badge;
 
 		Params();
 	};
@@ -249,6 +251,8 @@ class LLButton
 	void			setImageDisabledSelected(LLPointer<LLUIImage> image);
 	void			setImageFlash(LLPointer<LLUIImage> image);
 	void			setImagePressed(LLPointer<LLUIImage> image);
+	
+	void			setBadgeLabel(const LLStringExplicit& label);
 
 	void			setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
 	BOOL			getCommitOnReturn() const { return mCommitOnReturn; }
@@ -267,6 +271,8 @@ class LLButton
 	LLPointer<LLUIImage> getImageUnselected() const	{ return mImageUnselected; }
 	LLPointer<LLUIImage> getImageSelected() const	{ return mImageSelected; }
 
+	void addBadgeToParentPanel();
+
 	LLFrameTimer	mMouseDownTimer;
 
 private:
@@ -357,6 +363,8 @@ class LLButton
 	bool						mForcePressedState;
 
 	LLFrameTimer				mFlashingTimer;
+	
+	LLBadge*					mBadge;
 };
 
 // Build time optimization, generate once in .cpp file
diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h
index a853999e945..ce7cb5b3e0f 100644
--- a/indra/llxuixml/llinitparam.h
+++ b/indra/llxuixml/llinitparam.h
@@ -34,6 +34,8 @@
 #include <boost/unordered_map.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include "llerror.h"
+
 namespace LLInitParam
 {
 	template<typename T> const T& defaultValue() { static T value; return value; }
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index a19eccf748c..0795e38366a 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -132,6 +132,12 @@
     <color
      name="AvatarListItemIconVoiceLeftColor"
      reference="AvatarListItemIconOfflineColor" />
+    <color
+     name="BadgeImageColor"
+     value="0.25 0.85 0.25 1.0" />
+    <color
+     name="BadgeLabelColor"
+     reference="White" />
     <color
      name="ButtonBorderColor"
      reference="Unused?" />
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 4f19dd9a6d3..2a78337f65e 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -72,6 +72,8 @@ with the same filename but different name
   <texture name="BackButton_Over" file_name="icons/back_arrow_over.png" preload="false" scale.left="22" scale.top="12" scale.right="25" scale.bottom="12" />
   <texture name="BackButton_Press" file_name="icons/back_arrow_press.png" preload="false" scale.left="22" scale.top="12" scale.right="25" scale.bottom="12" />
 
+  <texture name="Badge" file_name="widgets/Badge.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
+
   <texture name="Blank" file_name="Blank.png" preload="false" />
 
 
diff --git a/indra/newview/skins/default/textures/widgets/Badge.png b/indra/newview/skins/default/textures/widgets/Badge.png
new file mode 100644
index 0000000000000000000000000000000000000000..afda6b66b9fcb1e7e8e3e4ddbaaac4bbe41e8f0a
GIT binary patch
literal 1716
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
KMNUMnLSTXo{YA(C

literal 0
HcmV?d00001

diff --git a/indra/newview/skins/default/xui/en/widgets/badge.xml b/indra/newview/skins/default/xui/en/widgets/badge.xml
new file mode 100644
index 00000000000..4eb633ac0cf
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/badge.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- Additional attributes:
+   -->
+<badge font="SansSerifSmall"
+       image="Badge"
+       image_color="BadgeImageColor"
+       label_color="BadgeLabelColor"
+       location="top_left"
+       location_percent_hcenter="85"
+       location_percent_vcenter="85"
+       padding_horiz="7"
+       padding_vert="4"
+       >
+</badge>
-- 
GitLab