mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 14:16:50 +00:00
1393 lines
36 KiB
C++
1393 lines
36 KiB
C++
//========= 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());
|
|
}
|
|
}
|
|
|
|
|
|
|