//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include #include #include #include #include #include #include #include #include #include #include #include #include #include // memdbgon must be the last include file in a .cpp file!!! #include 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()); } }