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