Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1392 lines
36 KiB

//========= 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_LOCALIZE_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());
}
}