text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  // $NoKeywords: $
  //=============================================================================//
  
  #include <assert.h>
  #include <stdarg.h>
  #include <stdio.h>
  #include <ctype.h>
  
  #include <vgui/IInput.h>
  #include <vgui/ILocalize.h>
  #include <vgui/IPanel.h>
  #include <vgui/ISurface.h>
  #include <vgui/IScheme.h>
  #include <KeyValues.h>
  
  #include <vgui_controls/Label.h>
  #include <vgui_controls/Image.h>
  #include <vgui_controls/TextImage.h>
  #include <vgui_controls/Controls.h>
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include <tier0/memdbgon.h>
  
  using namespace vgui;
  
  #ifndef max
  #define max(a,b)            (((a) > (b)) ? (a) : (b))
  #endif
  
  DECLARE_BUILD_FACTORY_DEFAULT_TEXT( Label, Label );
  
  //-----------------------------------------------------------------------------
  // Purpose: Constructor
  //-----------------------------------------------------------------------------
  Label::Label(Panel *parent, const char *panelName, const char *text) : BaseClass(parent, panelName)
  {
  	Init();
  
  	_textImage = new TextImage(text);
  	_textImage->SetColor(Color(0, 0, 0, 0));
  	SetText(text);
  	_textImageIndex = AddImage(_textImage, 0);
  
  	REGISTER_COLOR_AS_OVERRIDABLE( _disabledFgColor2, "disabledfgcolor2_override" );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Constructor
  //-----------------------------------------------------------------------------
  Label::Label(Panel *parent, const char *panelName, const wchar_t *wszText) : BaseClass(parent, panelName)
  {
  	Init();
  
  	_textImage = new TextImage(wszText);
  	_textImage->SetColor(Color(0, 0, 0, 0));
  	SetText(wszText);
  	_textImageIndex = AddImage(_textImage, 0);
  
  	REGISTER_COLOR_AS_OVERRIDABLE( _disabledFgColor2, "disabledfgcolor2_override" );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Destructor
  //-----------------------------------------------------------------------------
  Label::~Label()
  {
  	delete _textImage;
  	delete [] _associateName;
  	delete [] _fontOverrideName;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Construct the label
  //-----------------------------------------------------------------------------
  void Label::Init()
  {
  	_contentAlignment = a_west;
  	_textColorState = CS_NORMAL;
  	_textInset[0] = 0;
  	_textInset[1] = 0;
  	_hotkey = 0;
  	_associate = NULL;
  	_associateName = NULL;
  	_fontOverrideName = NULL;
  	m_bWrap = false;
  	m_bCenterWrap = false;
  	m_bAutoWideToContents = false;
  	m_bUseProportionalInsets = false;
  	m_bAutoWideDirty = false;
  
  //	SetPaintBackgroundEnabled(false);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set whether the text is displayed bright or dull
  //-----------------------------------------------------------------------------
  void Label::SetTextColorState(EColorState state)
  {
  	if (_textColorState != state)
  	{
  		_textColorState = state;
  		InvalidateLayout();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the full size of the contained content
  //-----------------------------------------------------------------------------
  void Label::GetContentSize(int &wide, int &tall)
  {
  	if( GetFont() == INVALID_FONT ) // we haven't loaded our font yet, so load it now
  	{
  		IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  		if ( pScheme )
  		{
  			SetFont( pScheme->GetFont( "Default", IsProportional() ) );
  		}
  	}
  
  
  	int tx0, ty0, tx1, ty1;
  	ComputeAlignment(tx0, ty0, tx1, ty1);
  
  	// the +8 is padding to the content size
  	// the code which uses it should really set that itself; 
  	// however a lot of existing code relies on this
  	wide = (tx1 - tx0) + _textInset[0]; 
  
  	// get the size of the text image and remove it
  	int iWide, iTall;
  	_textImage->GetSize(iWide, iTall);
  	wide -=  iWide;
  	// get the full, untruncated (no elipsis) size of the text image.
  	_textImage->GetContentSize(iWide, iTall);
  	wide += iWide;
  
  	// addin the image offsets as well
  	for (int i=0; i < _imageDar.Size(); i++)
  		wide += _imageDar[i].offset;
  
  	tall = max((ty1 - ty0) + _textInset[1], iTall);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Calculate the keyboard key that is a hotkey 
  //-----------------------------------------------------------------------------
  wchar_t Label::CalculateHotkey(const char *text)
  {
  	for (const char *ch = text; *ch != 0; ch++)
  	{
  		if (*ch == '&')
  			{
  			// get the next character
  			ch++;
  
  			if (*ch == '&')
  			{
  				// just an &
  				continue;
  			}
  			else if (*ch == 0)
  			{
  				break;
  			}
  			else if (V_isalnum(*ch))
  			{
  				// found the hotkey
  				return (wchar_t)tolower(*ch);
  			}
  		}
  	}
  
  	return '\0';
  }
  
  wchar_t Label::CalculateHotkey(const wchar_t *text)
  {
  	if( text )
  	{
  		for (const wchar_t *ch = text; *ch != 0; ch++)
  		{
  			if (*ch == '&')
  			{
  				// get the next character
  				ch++;
  
  				if (*ch == '&')
  				{
  					// just an &
  					continue;
  				}
  				else if (*ch == 0)
  				{
  					break;
  				}
  				else if (iswalnum(*ch))
  				{
  					// found the hotkey
  					return (wchar_t)towlower(*ch);
  				}
  			}
  		}
  	}
  
  	return '\0';
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Check if this label has a hotkey that is the key passed in.
  //-----------------------------------------------------------------------------
  Panel *Label::HasHotkey(wchar_t key)
  {
  #ifdef VGUI_HOTKEYS_ENABLED
  	if ( iswalnum( key ) )
  		key = towlower( key );
  
  	if (_hotkey == key)
  		return this;
  #endif
  
  	return NULL;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the hotkey for this label
  //-----------------------------------------------------------------------------
  void Label::SetHotkey(wchar_t ch)
  {
  	_hotkey = ch;
  }
  
  wchar_t Label::GetHotKey()
  {
  	return _hotkey;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Handle a hotkey by passing on focus to associate
  //-----------------------------------------------------------------------------
  void Label::OnHotkeyPressed()
  {
  	// we can't accept focus, but if we are associated to a control give it to that
  	if (_associate.Get() && !IsBuildModeActive())
  	{
  		_associate->RequestFocus();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Redirect mouse pressed to giving focus to associate
  //-----------------------------------------------------------------------------
  void Label::OnMousePressed(MouseCode code)
  {
  	if (_associate.Get() && !IsBuildModeActive())
  	{
  		_associate->RequestFocus();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the text in the label
  //-----------------------------------------------------------------------------
  void Label::GetText(char *textOut, int bufferLen)
  {
  	_textImage->GetText(textOut, bufferLen);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Return the text in the label
  //-----------------------------------------------------------------------------
  void Label::GetText(wchar_t *textOut, int bufLenInBytes)
  {
  	_textImage->GetText(textOut, bufLenInBytes);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Take the string and looks it up in the localization file 
  //          to convert it to unicode
  //			Setting the text will not set the size of the label.
  //			Set the size explicitly or use setToContent()
  //-----------------------------------------------------------------------------
  void Label::SetText(const char *text)
  {
  	// if set to null, just make blank
  	if (!text)
  	{
  		text = "";
  	}
  
  	// let the text image do the translation itself
  	_textImage->SetText(text);
  
  	if( text[0] == '#' )
  	{
  		SetHotkey(CalculateHotkey(g_pVGuiLocalize->Find(text)));		
  	}
  	else
  	{	
  		SetHotkey(CalculateHotkey(text));
  	}
  
  	m_bAutoWideDirty = m_bAutoWideToContents;
  
  	InvalidateLayout();
  	Repaint();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set unicode text directly
  //-----------------------------------------------------------------------------
  void Label::SetText(const wchar_t *unicodeString, bool bClearUnlocalizedSymbol)
  {
  	m_bAutoWideDirty = m_bAutoWideToContents;
  
  	if ( unicodeString && _textImage->GetUText() && !Q_wcscmp(unicodeString,_textImage->GetUText()) )
  		return;
  
  	_textImage->SetText(unicodeString, bClearUnlocalizedSymbol);
  
  //!! need to calculate hotkey from translated string
  	SetHotkey(CalculateHotkey(unicodeString));
  
      InvalidateLayout();     // possible that the textimage needs to expand
  	Repaint();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: updates localized text
  //-----------------------------------------------------------------------------
  void Label::OnDialogVariablesChanged(KeyValues *dialogVariables )
  {
  	StringIndex_t index = _textImage->GetUnlocalizedTextSymbol();
  	if (index != INVALID_STRING_INDEX )
  	{
  		// reconstruct the string from the variables
  		wchar_t buf[1024];
  		g_pVGuiLocalize->ConstructString(buf, sizeof(buf), index, dialogVariables);
  		SetText(buf);
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Additional offset at the Start of the text (from whichever side it is aligned)
  //-----------------------------------------------------------------------------
  void Label::SetTextInset(int xInset, int yInset)
  {
  	_textInset[0] = xInset;
  	_textInset[1] = yInset;
  
  	int wide, tall;
  	GetSize( wide, tall);
  	_textImage->SetDrawWidth(wide - _textInset[0]);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void Label::GetTextInset(int *xInset, int *yInset )
  {
  	if ( xInset )
  	{
  		*xInset = _textInset[0];
  	}
  	if ( yInset )
  	{
  		*yInset = _textInset[1];
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the enabled state
  //-----------------------------------------------------------------------------
  void Label::SetEnabled(bool state)
  {
  	Panel::SetEnabled(state);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Calculates where in the panel the content resides
  // Input  : &tx0 - [out] position of the content
  //			&ty0 - 
  //			&tx1 - 
  //			&ty1 - 
  // Note:	horizontal alignment is west if the image dar has
  //			more than one image in it, this is because we use image sizes
  //			to determine layout in classes for example, Menu.
  //-----------------------------------------------------------------------------
  void Label::ComputeAlignment(int &tx0, int &ty0, int &tx1, int &ty1)
  {
  	int wide, tall;
  	GetPaintSize(wide, tall);
  	int tWide,tTall;
  
  	// text bounding box
  	tx0 = 0;
  	ty0 = 0;
  
  	// loop through all the images and calculate the complete bounds
  	int maxX = 0, maxY = 0;
  
  	int actualXAlignment = _contentAlignment;
  	for (int i = 0; i < _imageDar.Count(); i++)
  	{
  		TImageInfo &imageInfo = _imageDar[i];
  		IImage *image = imageInfo.image;
  		if (!image)
  			continue; // skip over null images
  
  		// add up the bounds
  		int iWide, iTall;
  		image->GetSize(iWide, iTall);
  		if (iWide > wide) // if the image is larger than the label just do a west alignment
  			actualXAlignment = Label::a_west;
  		
  		// get the max height
  		maxY = max(maxY, iTall);
  		maxX += iWide;
  
  		// add the offset to x
  		maxX += imageInfo.offset;
  	}
  
  	tWide = maxX;
  	tTall = maxY;
  	
  	// x align text
  	switch (actualXAlignment)
  	{
  		// left
  		case Label::a_northwest:
  		case Label::a_west:
  		case Label::a_southwest:
  		{
  			tx0 = 0;
  			break;
  		}
  		// center
  		case Label::a_north:
  		case Label::a_center:
  		case Label::a_south:
  		{
  			tx0 = (wide - tWide) / 2;
  			break;
  		}
  		// right
  		case Label::a_northeast:
  		case Label::a_east:
  		case Label::a_southeast:
  		{
  			tx0 = wide - tWide;
  			break;
  		}
  	}
  
  	// y align text
  	switch (_contentAlignment)
  	{
  		//top
  		case Label::a_northwest:
  		case Label::a_north:
  		case Label::a_northeast:
  		{
  			ty0 = 0;
  			break;
  		}
  		// center
  		case Label::a_west:
  		case Label::a_center:
  		case Label::a_east:
  		{
  			ty0 = (tall - tTall) / 2;
  			break;
  		}
  		// south
  		case Label::a_southwest:
  		case Label::a_south:
  		case Label::a_southeast:
  		{
  			ty0 = tall - tTall;
  			break;
  		}
  	}
  
  	tx1 = tx0 + tWide;
  	ty1 = ty0 + tTall;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: overridden main drawing function for the panel
  //-----------------------------------------------------------------------------
  void Label::Paint()
  {
  	int tx0, ty0, tx1, ty1;
  	ComputeAlignment(tx0, ty0, tx1, ty1);
  
  	// calculate who our associate is if we haven't already
  	if (_associateName)
  	{
  		SetAssociatedControl(FindSiblingByName(_associateName));
  		delete [] _associateName;
  		_associateName = NULL;
  	}
  
  	int labelWide, labelTall;
  	GetSize(labelWide, labelTall);
  	int x = tx0, y = _textInset[1] + ty0;
  	int imageYPos = 0; // a place to save the y offset for when we draw the disable version of the image
  
  	// draw the set of images
  	for (int i = 0; i < _imageDar.Count(); i++)
  	{
  		TImageInfo &imageInfo = _imageDar[i];
  		IImage *image = imageInfo.image;
  		if (!image)
  			continue; // skip over null images
  
  		// add the offset to x
  		x += imageInfo.offset;
  
  		// if this is the text image then add its inset to the left or from the right
  		if (i == _textImageIndex)
  		{
  			switch ( _contentAlignment )
  			{
  				// left
  				case Label::a_northwest:
  				case Label::a_west:
  				case Label::a_southwest:
  				{
  					x += _textInset[0];
  					break;
  				}
  				// right
  				case Label::a_northeast:
  				case Label::a_east:
  				case Label::a_southeast:
  				{
  					x -= _textInset[0];
  					break;
  				}
  			}
  		}
  
  		// see if the image is in a fixed position
  		if (imageInfo.xpos >= 0)
  		{
  			x = imageInfo.xpos;
  		}
  
  		// draw
  		imageYPos = y;
  		image->SetPos(x, y);
  
  		// fix up y for center-aligned text
  		if (_contentAlignment == Label::a_west || _contentAlignment == Label::a_center || _contentAlignment == Label::a_east)
  		{
  			int iw, it;
  			image->GetSize(iw, it);
  			if (it < (ty1 - ty0))
  			{
  				imageYPos = ((ty1 - ty0) - it) / 2 + y;
  				image->SetPos(x, ((ty1 - ty0) - it) / 2 + y);
  			}
  		}
  
  		// don't resize the image unless its too big
  		if (imageInfo.width >= 0)
  		{
  			int w, t;
  			image->GetSize(w, t);
  			if (w > imageInfo.width)
  			{
  				image->SetSize(imageInfo.width, t);
  			}
  		}
  
  		// if it's the basic text image then draw specially
  		if (image == _textImage)
  		{
  			if (IsEnabled())
  			{
  				if (_associate.Get() && ipanel()->HasParent(input()->GetFocus(), _associate->GetVPanel()))
  				{
  					_textImage->SetColor(_associateColor);
  				}
  				else
  				{
  					_textImage->SetColor(GetFgColor());
  				}
  
  				_textImage->Paint();
  			}
  			else
  			{
  				// draw disabled version, with embossed look
  				// offset image
  				_textImage->SetPos(x + 1, imageYPos + 1);
  				_textImage->SetColor(_disabledFgColor1);
  				_textImage->Paint();
  
  				surface()->DrawFlushText();
  
  				// overlayed image
  				_textImage->SetPos(x, imageYPos);
  				_textImage->SetColor(_disabledFgColor2);
  				_textImage->Paint();
  			}
  		}
  		else
  		{
  			image->Paint();
  		}
  
  		// add the image size to x
  		int wide, tall;
  		image->GetSize(wide, tall);
  		x += wide;
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Helper function, draws a simple line with dashing parameters
  //-----------------------------------------------------------------------------
  void Label::DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen)
  {
  	// work out which way the line goes
  	if ((x1 - x0) > (y1 - y0))
  	{
  		// x direction line
  		while (1)
  		{
  			if (x0 + dashLen > x1)
  			{
  				// draw partial
  				surface()->DrawFilledRect(x0, y0, x1, y1);
  			}
  			else
  			{
  				surface()->DrawFilledRect(x0, y0, x0 + dashLen, y1);
  			}
  
  			x0 += dashLen;
  
  			if (x0 + gapLen > x1)
  				break;
  
  			x0 += gapLen;
  		}
  	}
  	else
  	{
  		// y direction
  		while (1)
  		{
  			if (y0 + dashLen > y1)
  			{
  				// draw partial
  				surface()->DrawFilledRect(x0, y0, x1, y1);
  			}
  			else
  			{
  				surface()->DrawFilledRect(x0, y0, x1, y0 + dashLen);
  			}
  
  			y0 += dashLen;
  
  			if (y0 + gapLen > y1)
  				break;
  
  			y0 += gapLen;
  		}
  	}
  }
  
  void Label::SetContentAlignment(Alignment alignment)
  {
  	_contentAlignment=alignment;
  	Repaint();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Size the width of the label to its contents - only works from in ApplySchemeSettings or PerformLayout()
  //-----------------------------------------------------------------------------
  void Label::SizeToContents()
  {
  	int wide, tall;
  	GetContentSize(wide, tall);
  
  	SetSize(wide, tall);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the font the text is drawn in
  //-----------------------------------------------------------------------------
  void Label::SetFont(HFont font)
  {
  	_textImage->SetFont(font);
  	Repaint();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Resond to resizing of the panel
  //-----------------------------------------------------------------------------
  void Label::OnSizeChanged(int wide, int tall)
  {
  	InvalidateLayout();
  	Panel::OnSizeChanged(wide, tall);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Get the font the textImage is drawn in.
  //-----------------------------------------------------------------------------
  HFont Label::GetFont()
  {
  	return _textImage->GetFont();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the foreground color of the Label
  //-----------------------------------------------------------------------------
  void Label::SetFgColor(Color color)
  {
  	if (!(GetFgColor() == color))
  	{
  		BaseClass::SetFgColor(color);
  		_textImage->SetColor(color);
  		Repaint();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Get the foreground color of the Label
  //-----------------------------------------------------------------------------
  Color Label::GetFgColor()
  {
  	Color clr = Panel::GetFgColor();
  	return clr;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the foreground color 1 color of the Label
  //-----------------------------------------------------------------------------
  void Label::SetDisabledFgColor1(Color color)
  {
  	_disabledFgColor1 = color;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void Label::SetDisabledFgColor2(Color color)
  {
  	_disabledFgColor2 = color;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  Color Label::GetDisabledFgColor1()
  {
  	return _disabledFgColor1;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  Color Label::GetDisabledFgColor2()
  {
  	return _disabledFgColor2;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  TextImage *Label::GetTextImage()
  {
  	return _textImage;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  bool Label::RequestInfo(KeyValues *outputData)
  {
  	if (!stricmp(outputData->GetName(), "GetText"))
  	{
  		wchar_t wbuf[256];
  		_textImage->GetText(wbuf, 255);
  		outputData->SetWString("text", wbuf);
  		return true;
  	}
  
  	return Panel::RequestInfo(outputData);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Sets the text from the message
  //-----------------------------------------------------------------------------
  void Label::OnSetText(KeyValues *params)
  {
  	KeyValues *pkvText = params->FindKey("text", false);
  	if (!pkvText)
  		return;
  
  	if (pkvText->GetDataType() == KeyValues::TYPE_STRING)
  	{
  		SetText(pkvText->GetString());
  	}
  	else if (pkvText->GetDataType() == KeyValues::TYPE_WSTRING)
  	{
  		SetText(pkvText->GetWString());
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Add an image to the list
  //			returns the index the image was placed in
  //-----------------------------------------------------------------------------
  int Label::AddImage(IImage *image, int offset)
  {
  	int newImage = _imageDar.AddToTail();
  	_imageDar[newImage].image = image;
  	_imageDar[newImage].offset = (short)offset;
  	_imageDar[newImage].xpos = -1;
  	_imageDar[newImage].width = -1;
  	InvalidateLayout();
  	return newImage;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: removes all images from the list
  //			user is responsible for the memory
  //-----------------------------------------------------------------------------
  void Label::ClearImages()
  {
  	_imageDar.RemoveAll();
  	_textImageIndex = -1;
  }
  
  void Label::ResetToSimpleTextImage()
  {
  	ClearImages();
  	_textImageIndex = AddImage(_textImage, 0);
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Multiple image handling
  //			Images are drawn from left to right across the label, ordered by index
  //			By default there is a TextImage in position 0
  //			Set the contents of an IImage in the IImage array.
  //-----------------------------------------------------------------------------
  void Label::SetImageAtIndex(int index, IImage *image, int offset)
  {
  	EnsureImageCapacity(index);
  //	Assert( image );
  
  	if ( _imageDar[index].image != image || _imageDar[index].offset != offset)
  	{
  		_imageDar[index].image = image;
  		_imageDar[index].offset = (short)offset;
  		InvalidateLayout();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Get an IImage in the IImage array.
  //-----------------------------------------------------------------------------
  IImage *Label::GetImageAtIndex(int index)
  {
  	if ( _imageDar.IsValidIndex( index ) )
  		return _imageDar[index].image;
  	return NULL;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Get the number of images in the array.
  //-----------------------------------------------------------------------------
  int Label::GetImageCount()
  {
  	return _imageDar.Count();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Move where the default text image is within the image array 
  //			(it starts in position 0)
  // Input  : newIndex - 
  // Output : int - the index the default text image was previously in
  //-----------------------------------------------------------------------------
  int Label::SetTextImageIndex(int newIndex)
  {
  	if (newIndex == _textImageIndex)
  		return _textImageIndex;
  
  	EnsureImageCapacity(newIndex);
  
  	int oldIndex = _textImageIndex;
  	if ( _textImageIndex >= 0 )
  	{
  		_imageDar[_textImageIndex].image = NULL;
  	}
  	if (newIndex > -1)
  	{
  		_imageDar[newIndex].image = _textImage;
  	}
  	_textImageIndex = newIndex;
  	return oldIndex;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Ensure that the maxIndex will be a valid index
  //-----------------------------------------------------------------------------
  void Label::EnsureImageCapacity(int maxIndex)
  {
  	while (_imageDar.Size() <= maxIndex)
  	{
  		AddImage(NULL, 0);
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Set the offset in pixels before the image
  //-----------------------------------------------------------------------------
  void Label::SetImagePreOffset(int index, int preOffset)
  {
  	if (_imageDar.IsValidIndex(index) && _imageDar[index].offset != preOffset)
  	{
  		_imageDar[index].offset = (short)preOffset;
  		InvalidateLayout();
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: fixes the layout bounds of the image within the label
  //-----------------------------------------------------------------------------
  void Label::SetImageBounds(int index, int x, int width)
  {
  	_imageDar[index].xpos = (short)x;
  	_imageDar[index].width = (short)width;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Labels can be associated with controls, and alter behaviour based on the associates behaviour
  //			If the associate is disabled, so are we
  //			If the associate has focus, we may alter how we draw
  //			If we get a hotkey press or focus message, we forward the focus to the associate
  //-----------------------------------------------------------------------------
  void Label::SetAssociatedControl(Panel *control)
  {
  	if (control != this)
  	{
  		_associate = control;
  	}
  	else
  	{
  		// don't let the associate ever be set to be ourself
  		_associate = NULL;
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Called after a panel requests focus to fix up the whole chain
  //-----------------------------------------------------------------------------
  void Label::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel)
  {
  	if (_associate.Get() && subFocus == GetVPanel() && !IsBuildModeActive())
  	{
  		// we've received focus; pass the focus onto the associate instead
  		_associate->RequestFocus();
  	}
  	else
  	{
  		BaseClass::OnRequestFocus(subFocus, defaultPanel);
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: sets custom settings from the scheme file
  //-----------------------------------------------------------------------------
  void Label::ApplySchemeSettings(IScheme *pScheme)
  {
  	BaseClass::ApplySchemeSettings(pScheme);
  
  	if (_fontOverrideName)
  	{
  		// use the custom specified font since we have one set
  		SetFont(pScheme->GetFont(_fontOverrideName, IsProportional()));
  	}
  	if ( GetFont() == INVALID_FONT )
  	{
  		SetFont( pScheme->GetFont( "Default", IsProportional() ) );
  	}	
  
  	if ( m_bWrap || m_bCenterWrap )
  	{
  		//tell it how big it is
  		int wide, tall;
  		Panel::GetSize(wide, tall);
  		wide -= _textInset[0];		// take inset into account
  		_textImage->SetSize(wide, tall);
  
  		_textImage->RecalculateNewLinePositions();
  	}
  	else
  	{
  		// if you don't set the size of the image, many, many buttons will break - we might want to look into fixing this all over the place later
  		int wide, tall;
  		_textImage->GetContentSize(wide, tall);
  		_textImage->SetSize(wide, tall);
  	}
  
  	if ( m_bAutoWideToContents )
  	{
  		m_bAutoWideDirty = true;
  		HandleAutoSizing();
  	}
  
  	// clear out any the images, since they will have been invalidated
  	for (int i = 0; i < _imageDar.Count(); i++)
  	{
  		IImage *image = _imageDar[i].image;
  		if (!image)
  			continue; // skip over null images
  
  		if (i == _textImageIndex)
  			continue;
  
  		_imageDar[i].image = NULL;
  	}
  
  	SetDisabledFgColor1(GetSchemeColor("Label.DisabledFgColor1", pScheme));
  	SetDisabledFgColor2(GetSchemeColor("Label.DisabledFgColor2", pScheme));
  	SetBgColor(GetSchemeColor("Label.BgColor", pScheme));
  
  	switch (_textColorState)
  	{
  	case CS_DULL:
  		SetFgColor(GetSchemeColor("Label.TextDullColor", pScheme));
  		break;
  	case CS_BRIGHT:
  		SetFgColor(GetSchemeColor("Label.TextBrightColor", pScheme));
  		break;
  	case CS_NORMAL:
  	default:
  		SetFgColor(GetSchemeColor("Label.TextColor", pScheme));
  		break;
  	}
  
  	_associateColor = GetSchemeColor("Label.SelectedTextColor", pScheme);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void Label::GetSettings( KeyValues *outResourceData )
  {
  	// panel settings
  	Panel::GetSettings( outResourceData );
  
  	// label settings
  	char buf[256];
  	_textImage->GetUnlocalizedText( buf, 255 );
  	if (!strnicmp(buf, "#var_", 5))
  	{
  		// strip off the variable prepender on save
  		outResourceData->SetString( "labelText", buf + 5 );
  	}
  	else
  	{
  		outResourceData->SetString( "labelText", buf );
  	}
  
  	const char *alignmentString = "";
  	switch ( _contentAlignment )
  	{
  	case a_northwest:	alignmentString = "north-west";	break;
  	case a_north:		alignmentString = "north";		break;
  	case a_northeast:	alignmentString = "north-east";	break;
  	case a_center:		alignmentString = "center";		break;
  	case a_east:		alignmentString = "east";		break;
  	case a_southwest:	alignmentString = "south-west";	break;
  	case a_south:		alignmentString = "south";		break;
  	case a_southeast:	alignmentString = "south-east";	break;
  	case a_west:	
  	default:			alignmentString = "west";	break;
  	}
  
  	outResourceData->SetString( "textAlignment", alignmentString );
  
  	if (_associate)
  	{
  		outResourceData->SetString("associate", _associate->GetName());
  	}
  
  	outResourceData->SetInt("dulltext", (int)(_textColorState == CS_DULL));
  	outResourceData->SetInt("brighttext", (int)(_textColorState == CS_BRIGHT));
  
  	if (_fontOverrideName)
  	{
  		outResourceData->SetString("font", _fontOverrideName);
  	}
  	
  	outResourceData->SetInt("wrap", ( m_bWrap ? 1 : 0 ));
  	outResourceData->SetInt("centerwrap", ( m_bCenterWrap ? 1 : 0 ));
  
  	if ( m_bUseProportionalInsets )
  	{
  		outResourceData->SetInt("textinsetx", scheme()->GetProportionalNormalizedValueEx( GetScheme(), _textInset[0] ) );
  		outResourceData->SetInt("textinsety", _textInset[1]);
  	}
  	else
  	{
  		outResourceData->SetInt("textinsetx", _textInset[0]);
  		outResourceData->SetInt("textinsety", _textInset[1]);
  	}
  	outResourceData->SetInt("auto_wide_tocontents", ( m_bAutoWideToContents ? 1 : 0 ));
  	outResourceData->SetInt("use_proportional_insets", ( m_bUseProportionalInsets ? 1 : 0 ));
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void Label::ApplySettings( KeyValues *inResourceData )
  {
  	BaseClass::ApplySettings( inResourceData );
  
  	// label settings
  	const char *labelText =	inResourceData->GetString( "labelText", NULL );
  	if ( labelText )
  	{
  		if (labelText[0] == '%' && labelText[strlen(labelText) - 1] == '%')
  		{
  			// it's a variable, set it to be a special variable localized string
  			wchar_t unicodeVar[256];
  			g_pVGuiLocalize->ConvertANSIToUnicode(labelText, unicodeVar, sizeof(unicodeVar));
  
  			char var[256];
  			_snprintf(var, sizeof(var), "#var_%s", labelText);
  			g_pVGuiLocalize->AddString(var + 1, unicodeVar, "");
  			SetText(var);
  		}
  		else
  		{
  			SetText(labelText);
  		}
  	}
  
  	// text alignment
  	const char *alignmentString = inResourceData->GetString( "textAlignment", "" );
  	int align = -1;
  
  	if ( !stricmp(alignmentString, "north-west") )
  	{
  		align = a_northwest;
  	}
  	else if ( !stricmp(alignmentString, "north") )
  	{
  		align = a_north;
  	}
  	else if ( !stricmp(alignmentString, "north-east") )
  	{
  		align = a_northeast;
  	}
  	else if ( !stricmp(alignmentString, "west") )
  	{
  		align = a_west;
  	}
  	else if ( !stricmp(alignmentString, "center") )
  	{
  		align = a_center;
  	}
  	else if ( !stricmp(alignmentString, "east") )
  	{
  		align = a_east;
  	}
  	else if ( !stricmp(alignmentString, "south-west") )
  	{
  		align = a_southwest;
  	}
  	else if ( !stricmp(alignmentString, "south") )
  	{
  		align = a_south;
  	}
  	else if ( !stricmp(alignmentString, "south-east") )
  	{
  		align = a_southeast;
  	}
  
  	if ( align != -1 )
  	{
  		SetContentAlignment( (Alignment)align );
  	}
  
  	// the control we are to be associated with may not have been created yet,
  	// so keep a pointer to it's name and calculate it when we can
  	const char *associateName = inResourceData->GetString("associate", "");
  	if (associateName[0] != 0)
  	{
  		int len = Q_strlen(associateName) + 1;
  		_associateName = new char[ len ];
  		Q_strncpy( _associateName, associateName, len );
  	}
  
  	if (inResourceData->GetInt("dulltext", 0) == 1)
  	{
  		SetTextColorState(CS_DULL);
  	}
  	else if (inResourceData->GetInt("brighttext", 0) == 1)
  	{
  		SetTextColorState(CS_BRIGHT);
  	}
  	else
  	{
  		SetTextColorState(CS_NORMAL);
  	}
  
  	// font settings
  	const char *overrideFont = inResourceData->GetString("font", "");
  	IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  
  	if (*overrideFont)
  	{
  		delete [] _fontOverrideName;
  		int len = Q_strlen(overrideFont) + 1;
  		_fontOverrideName = new char[ len ];
  		Q_strncpy(_fontOverrideName, overrideFont, len );
  		SetFont(pScheme->GetFont(_fontOverrideName, IsProportional()));
  	}
  	else if (_fontOverrideName)
  	{
  		delete [] _fontOverrideName;
  		_fontOverrideName = NULL;
  		SetFont(pScheme->GetFont("Default", IsProportional()));
  	}
  
  	bool bWrapText = inResourceData->GetInt("centerwrap", 0) > 0;
  	SetCenterWrap( bWrapText );
  
  	m_bAutoWideToContents = inResourceData->GetInt("auto_wide_tocontents", 0) > 0;
  
  	bWrapText = inResourceData->GetInt("wrap", 0) > 0;
  	SetWrap( bWrapText );
  
  	int inset_x = inResourceData->GetInt("textinsetx", _textInset[0]);
  	int inset_y = inResourceData->GetInt("textinsety", _textInset[1]);
  	// Had to play it safe and add a new key for backwards compatibility
  	m_bUseProportionalInsets = inResourceData->GetInt("use_proportional_insets", 0) > 0;
  	if ( m_bUseProportionalInsets )
  	{
  		inset_x = scheme()->GetProportionalScaledValueEx( GetScheme(), inset_x );
  	}
  
  	SetTextInset( inset_x, inset_y );
  
  	bool bAllCaps = inResourceData->GetInt("allcaps", 0) > 0;
  	SetAllCaps( bAllCaps );
  
  	InvalidateLayout(true);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Returns a description of the label string
  //-----------------------------------------------------------------------------
  const char *Label::GetDescription( void )
  {
  	static char buf[1024];
  	Q_snprintf(buf, sizeof(buf), "%s, string labelText, string associate, alignment textAlignment, int wrap, int dulltext, int brighttext, string font", BaseClass::GetDescription());
  	return buf;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: If a label has images in _imageDar, the size
  //			must take those into account as well as the textImage part
  //			Textimage part will shrink ONLY if there is not enough room.
  //-----------------------------------------------------------------------------
  void Label::PerformLayout()
  {
  	int wide, tall;
  	Panel::GetSize(wide, tall);
  	wide -= _textInset[0]; // take inset into account
  
  	// if we just have a textImage, this is trivial.
  	if (_imageDar.Count() == 1 && _textImageIndex == 0)
  	{	
  		if ( m_bWrap || m_bCenterWrap )
  		{
  			int twide, ttall;
  			_textImage->GetContentSize(twide, ttall);
  			_textImage->SetSize(wide, ttall);
  		}
  		else
  		{
  			int twide, ttall;
  			_textImage->GetContentSize(twide, ttall);
  			
  			// tell the textImage how much space we have to draw in
  			if ( wide < twide)
  				_textImage->SetSize(wide, ttall);
  			else
  				_textImage->SetSize(twide, ttall);
  		}
  
  		HandleAutoSizing();
  
  		HandleAutoSizing();
  
  		return;
  	}
  
  	// assume the images in the dar cannot be resized, and if
  	// the images + the textimage are too wide we shring the textimage part
  	if (_textImageIndex < 0)
  		return;
  	
  	// get the size of the images
  	int	widthOfImages = 0;
  	for (int i = 0; i < _imageDar.Count(); i++)
  	{
  		TImageInfo &imageInfo = _imageDar[i];
  		IImage *image = imageInfo.image;
  		if (!image)
  			continue; // skip over null images
  
  		if (i == _textImageIndex)
  			continue;
  
  		// add up the bounds
  		int iWide, iTall;
  		image->GetSize(iWide, iTall);		
  		widthOfImages += iWide;
  	}
  
  	// so this is how much room we have to draw the textimage part
  	int spaceAvail = wide - widthOfImages;
  
  	// if we have no space at all just leave everything as is.
  	if (spaceAvail < 0)
  		return;
  
  	int twide, ttall;
  	_textImage->GetSize (twide, ttall);
  	// tell the textImage how much space we have to draw in
  	_textImage->SetSize(spaceAvail, ttall);	
  
  	HandleAutoSizing();
  }
  
  void Label::SetWrap( bool bWrap )
  {
  	m_bWrap = bWrap;
  	_textImage->SetWrap( m_bWrap );
  
  	InvalidateLayout();
  }
  
  void Label::SetCenterWrap( bool bWrap )
  {
  	m_bCenterWrap = bWrap;
  	_textImage->SetCenterWrap( m_bCenterWrap );
  
  	InvalidateLayout();
  }
  
  void Label::SetAllCaps( bool bAllCaps )
  {
  	m_bAllCaps = bAllCaps;
  	_textImage->SetAllCaps( m_bAllCaps );
  
  	InvalidateLayout();
  }
  
  void Label::HandleAutoSizing( void )
  {
  	if ( m_bAutoWideDirty )
  	{
  		m_bAutoWideDirty = false;
  
  		// Only change our width to match our content
  		int wide, tall;
  		GetContentSize(wide, tall);
  		SetSize(wide, GetTall());
  	}
  }
  
  
  
  