aboutsummaryrefslogtreecommitdiff
path: root/mp/src/vgui2/vgui_controls/TextImage.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/vgui2/vgui_controls/TextImage.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/vgui2/vgui_controls/TextImage.cpp')
-rw-r--r--mp/src/vgui2/vgui_controls/TextImage.cpp1970
1 files changed, 985 insertions, 985 deletions
diff --git a/mp/src/vgui2/vgui_controls/TextImage.cpp b/mp/src/vgui2/vgui_controls/TextImage.cpp
index d4825ad7..61532126 100644
--- a/mp/src/vgui2/vgui_controls/TextImage.cpp
+++ b/mp/src/vgui2/vgui_controls/TextImage.cpp
@@ -1,985 +1,985 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implementation of vgui::TextImage control
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include <string.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <assert.h>
-#include <malloc.h>
-
-#include <vgui/IPanel.h>
-#include <vgui/ISurface.h>
-#include <vgui/IScheme.h>
-#include <vgui/IInput.h>
-#include <vgui/ILocalize.h>
-#include <KeyValues.h>
-
-#include <vgui_controls/TextImage.h>
-#include <vgui_controls/Controls.h>
-
-#include "tier0/dbg.h"
-// memdbgon must be the last include file in a .cpp file!!!
-#include <tier0/memdbgon.h>
-
-// enable this define if you want unlocalized strings logged to files unfound.txt and unlocalized.txt
-// #define LOG_UNLOCALIZED_STRINGS
-
-using namespace vgui;
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-TextImage::TextImage(const char *text) : Image()
-{
- _utext = NULL;
- _textBufferLen = 0;
- _font = INVALID_FONT;
- _fallbackFont = INVALID_FONT;
- _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
- _drawWidth = 0;
- _textBufferLen = 0;
- _textLen = 0;
- m_bWrap = false;
- m_bWrapCenter = false;
- m_LineBreaks.RemoveAll();
- m_LineXIndent.RemoveAll();
- m_pwszEllipsesPosition = NULL;
- m_bUseFallbackFont = false;
- m_bRenderUsingFallbackFont = false;
- m_bAllCaps = false;
-
- SetText(text); // set the text.
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-TextImage::TextImage(const wchar_t *wszText) : Image()
-{
- _utext = NULL;
- _textBufferLen = 0;
- _font = INVALID_FONT;
- _fallbackFont = INVALID_FONT;
- _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
- _drawWidth = 0;
- _textBufferLen = 0;
- _textLen = 0;
- m_bWrap = false;
- m_bWrapCenter = false;
- m_LineBreaks.RemoveAll();
- m_LineXIndent.RemoveAll();
- m_bUseFallbackFont = false;
- m_bRenderUsingFallbackFont = false;
- m_bAllCaps = false;
-
- SetText(wszText); // set the text.
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-TextImage::~TextImage()
-{
- delete [] _utext;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: takes the string and looks it up in the localization file to convert it to unicode
-//-----------------------------------------------------------------------------
-void TextImage::SetText(const char *text)
-{
- if (!text)
- {
- text = "";
- }
-
- // check for localization
- if (*text == '#')
- {
- // try lookup in localization tables
- _unlocalizedTextSymbol = g_pVGuiLocalize->FindIndex(text + 1);
-
- if (_unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX)
- {
- wchar_t *unicode = g_pVGuiLocalize->GetValueByIndex(_unlocalizedTextSymbol);
- SetText(unicode);
- return;
- }
- else
- {
- // could not find string
- // debug code for logging unlocalized strings
-#if defined(LOG_UNLOCALIZED_STRINGS)
- if (*text)
- {
- // write out error to unfound.txt log file
- static bool first = true;
- FILE *f;
- if (first)
- {
- first = false;
- f = fopen("unfound.txt", "wt");
- }
- else
- {
- f = fopen("unfound.txt", "at");
- }
-
- if (f)
- {
- fprintf(f, "\"%s\"\n", text);
- fclose(f);
- }
- }
-#endif // LOG_UNLOCALIZED_STRINGS
- }
- }
- else
- {
- // debug code for logging unlocalized strings
-#if defined(LOG_UNLOCALIZED_STRINGS)
- if (text[0])
- {
- // setting a label to be ANSI text, write out error to unlocalized.txt log file
- static bool first = true;
- FILE *f;
- if (first)
- {
- first = false;
- f = fopen("unlocalized.txt", "wt");
- }
- else
- {
- f = fopen("unlocalized.txt", "at");
- }
- if (f)
- {
- fprintf(f, "\"%s\"\n", text);
- fclose(f);
- }
- }
-#endif // LOG_UNLOCALIZED_STRINGS
- }
-
- // convert the ansi string to unicode and use that
- wchar_t unicode[1024];
- g_pVGuiLocalize->ConvertANSIToUnicode(text, unicode, sizeof(unicode));
- SetText(unicode);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets the width that the text can be.
-//-----------------------------------------------------------------------------
-void TextImage::SetDrawWidth(int width)
-{
- _drawWidth = width;
- m_bRecalculateTruncation = true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the width that the text can be.
-//-----------------------------------------------------------------------------
-void TextImage::GetDrawWidth(int &width)
-{
- width = _drawWidth;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: sets unicode text directly
-//-----------------------------------------------------------------------------
-void TextImage::SetText(const wchar_t *unicode, bool bClearUnlocalizedSymbol)
-{
- if ( bClearUnlocalizedSymbol )
- {
- // Clear out unlocalized text symbol so that changing dialog variables
- // doesn't stomp over the custom unicode string we're being set to.
- _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
- }
-
- if (!unicode)
- {
- unicode = L"";
- }
-
- // reallocate the buffer if necessary
- _textLen = (short)wcslen(unicode);
- if (_textLen >= _textBufferLen)
- {
- delete [] _utext;
- _textBufferLen = (short)(_textLen + 1);
- _utext = new wchar_t[_textBufferLen];
- }
-
- m_LineBreaks.RemoveAll();
- m_LineXIndent.RemoveAll();
-
- // store the text as unicode
- wcscpy(_utext, unicode);
-
- m_bRecalculateTruncation = true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the text in the textImage
-//-----------------------------------------------------------------------------
-void TextImage::GetText(char *buffer, int bufferSize)
-{
- g_pVGuiLocalize->ConvertUnicodeToANSI(_utext, buffer, bufferSize);
-
- if ( m_bAllCaps )
- {
- // Uppercase all the letters
- for ( int i = Q_strlen( buffer ); i >= 0; --i )
- {
- buffer[ i ] = toupper( buffer[ i ] );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the text in the textImage
-//-----------------------------------------------------------------------------
-void TextImage::GetText(wchar_t *buffer, int bufLenInBytes)
-{
- wcsncpy(buffer, _utext, bufLenInBytes / sizeof(wchar_t));
-
- if ( m_bAllCaps )
- {
- // Uppercase all the letters
- for ( int i = Q_wcslen( buffer ) - 1; i >= 0; --i )
- {
- buffer[ i ] = towupper( buffer[ i ] );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: data accessor
-//-----------------------------------------------------------------------------
-void TextImage::GetUnlocalizedText(char *buffer, int bufferSize)
-{
- if (_unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX)
- {
- const char *text = g_pVGuiLocalize->GetNameByIndex(_unlocalizedTextSymbol);
- buffer[0] = '#';
- Q_strncpy(buffer + 1, text, bufferSize - 1);
- buffer[bufferSize-1] = 0;
- }
- else
- {
- GetText(buffer, bufferSize);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: unlocalized text symbol
-//-----------------------------------------------------------------------------
-StringIndex_t TextImage::GetUnlocalizedTextSymbol()
-{
- return _unlocalizedTextSymbol;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Changes the current font
-//-----------------------------------------------------------------------------
-void TextImage::SetFont(HFont font)
-{
- _font = font;
- m_bRecalculateTruncation = true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the font of the text.
-//-----------------------------------------------------------------------------
-HFont TextImage::GetFont()
-{
- if ( m_bRenderUsingFallbackFont )
- {
- return _fallbackFont;
- }
-
- return _font;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets the size of the TextImage. This is directly tied to drawWidth
-//-----------------------------------------------------------------------------
-void TextImage::SetSize(int wide, int tall)
-{
- Image::SetSize(wide, tall);
- _drawWidth = wide;
- m_bRecalculateTruncation = true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draw the Image on screen.
-//-----------------------------------------------------------------------------
-void TextImage::Paint()
-{
- int wide, tall;
- GetSize(wide, tall);
-
- if (!_utext || GetFont() == INVALID_FONT )
- return;
-
- if (m_bRecalculateTruncation)
- {
- if ( m_bWrap || m_bWrapCenter )
- {
- RecalculateNewLinePositions();
- }
-
- RecalculateEllipsesPosition();
- }
-
- DrawSetTextColor(GetColor());
- HFont font = GetFont();
- DrawSetTextFont(font);
-
- int lineHeight = surface()->GetFontTall(font);
- float x = 0.0f;
- int y = 0;
- int iIndent = 0;
- int iNextColorChange = 0;
-
- int px, py;
- GetPos(px, py);
-
- int currentLineBreak = 0;
-
- if ( m_bWrapCenter && m_LineXIndent.Count() )
- {
- x = m_LineXIndent[0];
- }
-
- for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
- {
- wchar_t ch = wsz[0];
-
- if ( m_bAllCaps )
- {
- ch = towupper( ch );
- }
-
- if ( m_ColorChangeStream.Count() > iNextColorChange )
- {
- if ( m_ColorChangeStream[iNextColorChange].textStreamIndex == (wsz - _utext) )
- {
- DrawSetTextColor( m_ColorChangeStream[iNextColorChange].color );
- iNextColorChange++;
- }
- }
-
- // check for special characters
- if ( ch == '\r' || ch <= 8 )
- {
- // ignore, just use \n for newlines
- continue;
- }
- else if (ch == '\n')
- {
- // newline
- iIndent++;
- if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() )
- {
- x = m_LineXIndent[iIndent];
- }
- else
- {
- x = 0;
- }
- y += lineHeight;
- continue;
- }
- else if (ch == '&')
- {
- // "&&" means draw a single ampersand, single one is a shortcut character
- if (wsz[1] == '&')
- {
- // just move on and draw the second ampersand
- wsz++;
- }
- else
- {
- // draw the underline, then continue to the next character without moving forward
-#ifdef VGUI_DRAW_HOTKEYS_ENABLED
- surface()->DrawSetTextPos(x + px, y + py);
- surface()->DrawUnicodeChar('_');
-#endif
- continue;
- }
- }
-
- // see if we've hit the truncated portion of the string
- if (wsz == m_pwszEllipsesPosition)
- {
- // string is truncated, draw ellipses
- for (int i = 0; i < 3; i++)
- {
- surface()->DrawSetTextPos(x + px, y + py);
- surface()->DrawUnicodeChar('.');
- x += surface()->GetCharacterWidth(font, '.');
- }
- break;
- }
-
- if (currentLineBreak != m_LineBreaks.Count())
- {
- if (wsz == m_LineBreaks[currentLineBreak])
- {
- // newline
- iIndent++;
- if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() )
- {
- x = m_LineXIndent[iIndent];
- }
- else
- {
- x = 0;
- }
-
- y += lineHeight;
- currentLineBreak++;
- }
- }
-
- // Underlined text wants to draw the spaces anyway
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( wsz > _utext )
- chBefore = wsz[-1];
- chAfter = wsz[1];
- float flWide = 0.0f, flabcA = 0.0f;
- surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
- if ( ch == L' ' )
- x = ceil( x );
-
- surface()->DrawSetTextPos( x + px, y + py);
- surface()->DrawUnicodeChar(ch);
- x += floor(flWide + 0.6);
-#else
- surface()->DrawSetTextPos( x + px, y + py);
- surface()->DrawUnicodeChar(ch);
- x += surface()->GetCharacterWidth(font, ch);
-#endif
- }
-
- // Useful debugging
- /*
- DrawSetColor(GetColor());
- DrawOutlinedRect( 0,0, _drawWidth, tall );
- */
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the size of a text string in pixels
-//-----------------------------------------------------------------------------
-void TextImage::GetTextSize(int &wide, int &tall)
-{
- wide = 0;
- tall = 0;
- int maxWide = 0;
- const wchar_t *text = _utext;
-
- HFont font = _font;
- if ( font == INVALID_FONT )
- return;
-
- if ( m_bWrap || m_bWrapCenter )
- {
- RecalculateNewLinePositions();
- }
-
- // For height, use the remapped font
- int fontHeight = surface()->GetFontTall(GetFont());
- tall = fontHeight;
-
- int textLen = wcslen(text);
- for (int i = 0; i < textLen; i++)
- {
- wchar_t ch = text[i];
-
- // handle stupid special characters, these should be removed
- if ( ch == '&' )
- {
- continue;
- }
-
- if ( m_bAllCaps )
- {
- ch = towupper( ch );
- }
-
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( i > 0 )
- chBefore = text[i-1];
- chAfter = text[i+1];
- float flWide = 0.0f, flabcA;
- surface()->GetKernedCharWidth( font, text[i], chBefore, chAfter, flWide, flabcA );
- if ( text[i] == L' ' )
- flWide = ceil( flWide );
- wide += floor( flWide + 0.6);
-#else
- int a, b, c;
- surface()->GetCharABCwide(font, ch, a, b, c);
- wide += (a + b + c);
-#endif
-
-
- if (ch == '\n')
- {
- tall += fontHeight;
- if(wide>maxWide)
- {
- maxWide=wide;
- }
- wide=0; // new line, wide is reset...
- }
-
- if ( m_bWrap || m_bWrapCenter )
- {
- for(int j=0; j<m_LineBreaks.Count(); j++)
- {
- if ( &text[i] == m_LineBreaks[j] )
- {
- tall += fontHeight;
- if(wide>maxWide)
- {
- maxWide=wide;
- }
- wide=0; // new line, wide is reset...
- }
- }
- }
-
- }
-#ifdef OSX
- wide += 2;
- if ( textLen < 3 )
- wide += 3;
-#endif
- if (wide < maxWide)
- {
- // maxWide only gets set if a newline is in the label
- wide = maxWide;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the size of the text in the image
-//-----------------------------------------------------------------------------
-void TextImage::GetContentSize(int &wide, int &tall)
-{
- GetTextSize(wide, tall);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Resize the text image to the content size
-//-----------------------------------------------------------------------------
-void TextImage::ResizeImageToContent()
-{
- int wide, tall;
- GetContentSize(wide, tall);
- SetSize(wide, tall);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Recalculates line breaks
-//-----------------------------------------------------------------------------
-void TextImage::RecalculateNewLinePositions()
-{
- HFont font = GetFont();
-
- int charWidth;
- int x = 0;
-
- //int wordStartIndex = 0;
- wchar_t *wordStartIndex = _utext;
- int wordLength = 0;
- bool hasWord = false;
- bool justStartedNewLine = true;
- bool wordStartedOnNewLine = true;
-
- int startChar = 0;
-
- // clear the line breaks list
- m_LineBreaks.RemoveAll();
- m_LineXIndent.RemoveAll();
-
- // handle the case where this char is a new line, in that case
- // we have already taken its break index into account above so skip it.
- if (_utext[startChar] == '\r' || _utext[startChar] == '\n')
- {
- startChar++;
- }
-
- // loop through all the characters
- for (wchar_t *wsz = &_utext[startChar]; *wsz != 0; wsz++)
- {
- // handle stupid special characters, these should be removed
- // 0x01, 0x02 and 0x03 are color escape characters and should be ignored
- if ( ( wsz[0] == '&' || wsz[0] == 0x01 || wsz[0] == 0x02 || wsz[0] == 0x03 ) && wsz[1] != 0 )
- {
- wsz++;
- }
-
- wchar_t ch = wsz[0];
-
- if ( m_bAllCaps )
- {
- ch = towupper( ch );
- }
-
- // line break only on whitespace characters
- if (!iswspace(ch))
- {
- if ( !hasWord )
- {
- // Start a new word
- wordStartIndex = wsz;
- hasWord = true;
- wordStartedOnNewLine = justStartedNewLine;
- wordLength = 0;
- }
- //else append to the current word
- }
- else
- {
- // whitespace/punctuation character
- // end the word
- hasWord = false;
- }
-
- // get the width
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( wsz > _utext )
- chBefore = wsz[-1];
- chAfter = wsz[1];
- float flWide = 0.0f, flabcA = 0.0f;
- surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
- charWidth = floor( flWide + 0.6 );
-#else
- charWidth = surface()->GetCharacterWidth(font, ch);
-#endif
- if (!iswcntrl(ch))
- {
- justStartedNewLine = false;
- }
-
- // check to see if the word is past the end of the line [wordStartIndex, i)
- if ((x + charWidth) > _drawWidth || ch == '\r' || ch == '\n')
- {
- justStartedNewLine = true;
- hasWord = false;
-
- if (ch == '\r' || ch == '\n')
- {
- // set the break at the current character
- //don't do this, paint will manually wrap on newline chars
- // m_LineBreaks.AddToTail(i);
- }
- else if (wordStartedOnNewLine)
- {
- // word is longer than a line, so set the break at the current cursor
- m_LineBreaks.AddToTail(wsz);
- }
- else
- {
- // set it at the last word Start
- m_LineBreaks.AddToTail(wordStartIndex);
-
- // just back to reparse the next line of text
- // ywb 8/1/07: Back off one extra char since the 'continue' will increment wsz for us by one in the for loop
- wsz = wordStartIndex - 1;
- }
-
- // reset word length
- wordLength = 0;
- x = 0;
- continue;
- }
-
- // add to the size
- x += charWidth;
- wordLength += charWidth;
- }
-
- RecalculateCenterWrapIndents();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Calculates where the text should be truncated
-//-----------------------------------------------------------------------------
-void TextImage::RecalculateEllipsesPosition()
-{
- m_bRecalculateTruncation = false;
- m_pwszEllipsesPosition = NULL;
-
- //don't insert ellipses on wrapped strings
- if ( m_bWrap || m_bWrapCenter )
- return;
-
- // don't truncate strings with newlines
- if (wcschr(_utext, '\n') != NULL)
- return;
-
- if ( _drawWidth == 0 )
- {
- int h;
- GetSize( _drawWidth, h );
- }
-
- for ( int check = 0; check < (m_bUseFallbackFont ? 2 : 1); ++check )
- {
- HFont font = GetFont();
- if ( check == 1 && _fallbackFont != INVALID_FONT )
- {
- m_pwszEllipsesPosition = NULL;
- font = _fallbackFont;
- m_bRenderUsingFallbackFont = true;
- }
-
- int ellipsesWidth = 3 * surface()->GetCharacterWidth(font, '.');
- int x = 0;
-
- for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
- {
- wchar_t ch = wsz[0];
-
- if ( m_bAllCaps )
- {
- ch = towupper( ch );
- }
-
- // check for special characters
- if (ch == '\r')
- {
- // ignore, just use \n for newlines
- continue;
- }
- else if (ch == '&')
- {
- // "&&" means draw a single ampersand, single one is a shortcut character
- if (wsz[1] == '&')
- {
- // just move on and draw the second ampersand
- wsz++;
- }
- else
- {
- continue;
- }
- }
-
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( wsz > _utext )
- chBefore = wsz[-1];
- chAfter = wsz[1];
- float flWide = 0.0f, flabcA = 0.0f;
- surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
- int len = floor( flWide + 0.6 );
-#else
- int len = surface()->GetCharacterWidth(font, ch);
-#endif
-
- // don't truncate the first character
- if (wsz == _utext)
- {
- x += len;
- continue;
- }
-
- if (x + len + ellipsesWidth > _drawWidth)
- {
- // potential have an ellipses, see if the remaining characters will fit
- int remainingLength = len;
- for (const wchar_t *rwsz = wsz + 1; *rwsz != 0; rwsz++)
- {
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( rwsz > _utext )
- chBefore = rwsz[-1];
- chAfter = rwsz[1];
- float flWide = 0.0f, flabcA = 0.0f;
- surface()->GetKernedCharWidth( font, *rwsz, chBefore, chAfter, flWide, flabcA );
- int len = floor( flWide + 0.6 );
- remainingLength += floor( flWide + 0.6 );
-#else
- remainingLength += surface()->GetCharacterWidth(font, *rwsz);
-#endif
- }
-
- if (x + remainingLength > _drawWidth)
- {
- // looks like we've got an ellipses situation
- m_pwszEllipsesPosition = wsz;
- break;
- }
- }
-
- x += len;
- }
-
- // Didn't need ellipses...
- if ( !m_pwszEllipsesPosition )
- break;
- }
-}
-
-void TextImage::SetWrap( bool bWrap )
-{
- m_bWrap = bWrap;
-}
-
-void TextImage::SetCenterWrap( bool bWrap )
-{
- m_bWrapCenter = bWrap;
-}
-
-
-void TextImage::SetUseFallbackFont( bool bState, HFont hFallback )
-{
- m_bUseFallbackFont = bState;
- _fallbackFont = hFallback;
-}
-
-void TextImage::SetAllCaps( bool bAllCaps )
-{
- m_bAllCaps = bAllCaps;
-}
-
-void TextImage::ResizeImageToContentMaxWidth( int nMaxWidth )
-{
- _drawWidth = nMaxWidth;
- // Since we might have to use the "fallback" font, go ahead and recalc the ellipses state first to see if that's the case
- // NOTE: I think there may be a race condition lurking here, but this seems to work.
- if ( m_bRecalculateTruncation )
- {
- if ( m_bWrap || m_bWrapCenter )
- {
- RecalculateNewLinePositions();
- }
-
- RecalculateEllipsesPosition();
- }
-
- ResizeImageToContent();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: For center wrapping of multi-line text images, determines the indent each line needs to be centered
-//-----------------------------------------------------------------------------
-void TextImage::RecalculateCenterWrapIndents()
-{
- m_LineXIndent.RemoveAll();
-
- if ( !m_bWrapCenter )
- return;
-
- if (!_utext || GetFont() == INVALID_FONT )
- return;
-
- HFont font = GetFont();
- int px, py;
- GetPos(px, py);
-
- int currentLineBreak = 0;
- int iCurLineW = 0;
-
- for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
- {
- wchar_t ch = wsz[0];
-
- if ( m_bAllCaps )
- {
- ch = towupper( ch );
- }
-
- // check for special characters
- if (ch == '\r')
- {
- // ignore, just use \n for newlines
- continue;
- }
- else if (ch == '\n')
- {
- int iIdx = m_LineXIndent.AddToTail();
- m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
-
- iCurLineW = 0;
- continue;
- }
- else if (ch == '&')
- {
- // "&&" means draw a single ampersand, single one is a shortcut character
- if (wsz[1] == '&')
- {
- // just move on and draw the second ampersand
- wsz++;
- }
- else
- {
- // draw the underline, then continue to the next character without moving forward
- continue;
- }
- }
-
- // Don't need to check ellipses, they're not used when wrapping
-
- if (currentLineBreak != m_LineBreaks.Count())
- {
- if (wsz == m_LineBreaks[currentLineBreak])
- {
- int iIdx = m_LineXIndent.AddToTail();
- m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
-
- iCurLineW = 0;
- currentLineBreak++;
- }
- }
-
-#if USE_GETKERNEDCHARWIDTH
- wchar_t chBefore = 0;
- wchar_t chAfter = 0;
- if ( wsz > _utext )
- chBefore = wsz[-1];
- chAfter = wsz[1];
- float flWide = 0.0f, flabcA = 0.0f;
- surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
- iCurLineW += floor( flWide + 0.6 );
-#else
- iCurLineW += surface()->GetCharacterWidth(font, ch);
-#endif
- }
-
- // Add the final line
- int iIdx = m_LineXIndent.AddToTail();
- m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
-}
-
-void TextImage::AddColorChange( Color col, int iTextStreamIndex )
-{
- label_colorchange_t tmpChange;
- tmpChange.color = col;
- tmpChange.textStreamIndex = iTextStreamIndex;
- m_ColorChangeStream.Insert( tmpChange );
-}
-
-void TextImage::SetColorChangeStream( CUtlSortVector<label_colorchange_t,CColorChangeListLess> *pUtlVecStream )
-{
- ClearColorChangeStream();
-
- m_ColorChangeStream = *pUtlVecStream;
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implementation of vgui::TextImage control
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <malloc.h>
+
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui/IInput.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/TextImage.h>
+#include <vgui_controls/Controls.h>
+
+#include "tier0/dbg.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+// enable this define if you want unlocalized strings logged to files unfound.txt and unlocalized.txt
+// #define LOG_UNLOCALIZED_STRINGS
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+TextImage::TextImage(const char *text) : Image()
+{
+ _utext = NULL;
+ _textBufferLen = 0;
+ _font = INVALID_FONT;
+ _fallbackFont = INVALID_FONT;
+ _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
+ _drawWidth = 0;
+ _textBufferLen = 0;
+ _textLen = 0;
+ m_bWrap = false;
+ m_bWrapCenter = false;
+ m_LineBreaks.RemoveAll();
+ m_LineXIndent.RemoveAll();
+ m_pwszEllipsesPosition = NULL;
+ m_bUseFallbackFont = false;
+ m_bRenderUsingFallbackFont = false;
+ m_bAllCaps = false;
+
+ SetText(text); // set the text.
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+TextImage::TextImage(const wchar_t *wszText) : Image()
+{
+ _utext = NULL;
+ _textBufferLen = 0;
+ _font = INVALID_FONT;
+ _fallbackFont = INVALID_FONT;
+ _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
+ _drawWidth = 0;
+ _textBufferLen = 0;
+ _textLen = 0;
+ m_bWrap = false;
+ m_bWrapCenter = false;
+ m_LineBreaks.RemoveAll();
+ m_LineXIndent.RemoveAll();
+ m_bUseFallbackFont = false;
+ m_bRenderUsingFallbackFont = false;
+ m_bAllCaps = false;
+
+ SetText(wszText); // set the text.
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+TextImage::~TextImage()
+{
+ delete [] _utext;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: takes the string and looks it up in the localization file to convert it to unicode
+//-----------------------------------------------------------------------------
+void TextImage::SetText(const char *text)
+{
+ if (!text)
+ {
+ text = "";
+ }
+
+ // check for localization
+ if (*text == '#')
+ {
+ // try lookup in localization tables
+ _unlocalizedTextSymbol = g_pVGuiLocalize->FindIndex(text + 1);
+
+ if (_unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX)
+ {
+ wchar_t *unicode = g_pVGuiLocalize->GetValueByIndex(_unlocalizedTextSymbol);
+ SetText(unicode);
+ return;
+ }
+ else
+ {
+ // could not find string
+ // debug code for logging unlocalized strings
+#if defined(LOG_UNLOCALIZED_STRINGS)
+ if (*text)
+ {
+ // write out error to unfound.txt log file
+ static bool first = true;
+ FILE *f;
+ if (first)
+ {
+ first = false;
+ f = fopen("unfound.txt", "wt");
+ }
+ else
+ {
+ f = fopen("unfound.txt", "at");
+ }
+
+ if (f)
+ {
+ fprintf(f, "\"%s\"\n", text);
+ fclose(f);
+ }
+ }
+#endif // LOG_UNLOCALIZED_STRINGS
+ }
+ }
+ else
+ {
+ // debug code for logging unlocalized strings
+#if defined(LOG_UNLOCALIZED_STRINGS)
+ if (text[0])
+ {
+ // setting a label to be ANSI text, write out error to unlocalized.txt log file
+ static bool first = true;
+ FILE *f;
+ if (first)
+ {
+ first = false;
+ f = fopen("unlocalized.txt", "wt");
+ }
+ else
+ {
+ f = fopen("unlocalized.txt", "at");
+ }
+ if (f)
+ {
+ fprintf(f, "\"%s\"\n", text);
+ fclose(f);
+ }
+ }
+#endif // LOG_UNLOCALIZED_STRINGS
+ }
+
+ // convert the ansi string to unicode and use that
+ wchar_t unicode[1024];
+ g_pVGuiLocalize->ConvertANSIToUnicode(text, unicode, sizeof(unicode));
+ SetText(unicode);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the width that the text can be.
+//-----------------------------------------------------------------------------
+void TextImage::SetDrawWidth(int width)
+{
+ _drawWidth = width;
+ m_bRecalculateTruncation = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the width that the text can be.
+//-----------------------------------------------------------------------------
+void TextImage::GetDrawWidth(int &width)
+{
+ width = _drawWidth;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets unicode text directly
+//-----------------------------------------------------------------------------
+void TextImage::SetText(const wchar_t *unicode, bool bClearUnlocalizedSymbol)
+{
+ if ( bClearUnlocalizedSymbol )
+ {
+ // Clear out unlocalized text symbol so that changing dialog variables
+ // doesn't stomp over the custom unicode string we're being set to.
+ _unlocalizedTextSymbol = INVALID_LOCALIZE_STRING_INDEX;
+ }
+
+ if (!unicode)
+ {
+ unicode = L"";
+ }
+
+ // reallocate the buffer if necessary
+ _textLen = (short)wcslen(unicode);
+ if (_textLen >= _textBufferLen)
+ {
+ delete [] _utext;
+ _textBufferLen = (short)(_textLen + 1);
+ _utext = new wchar_t[_textBufferLen];
+ }
+
+ m_LineBreaks.RemoveAll();
+ m_LineXIndent.RemoveAll();
+
+ // store the text as unicode
+ wcscpy(_utext, unicode);
+
+ m_bRecalculateTruncation = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the text in the textImage
+//-----------------------------------------------------------------------------
+void TextImage::GetText(char *buffer, int bufferSize)
+{
+ g_pVGuiLocalize->ConvertUnicodeToANSI(_utext, buffer, bufferSize);
+
+ if ( m_bAllCaps )
+ {
+ // Uppercase all the letters
+ for ( int i = Q_strlen( buffer ); i >= 0; --i )
+ {
+ buffer[ i ] = toupper( buffer[ i ] );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the text in the textImage
+//-----------------------------------------------------------------------------
+void TextImage::GetText(wchar_t *buffer, int bufLenInBytes)
+{
+ wcsncpy(buffer, _utext, bufLenInBytes / sizeof(wchar_t));
+
+ if ( m_bAllCaps )
+ {
+ // Uppercase all the letters
+ for ( int i = Q_wcslen( buffer ) - 1; i >= 0; --i )
+ {
+ buffer[ i ] = towupper( buffer[ i ] );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void TextImage::GetUnlocalizedText(char *buffer, int bufferSize)
+{
+ if (_unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX)
+ {
+ const char *text = g_pVGuiLocalize->GetNameByIndex(_unlocalizedTextSymbol);
+ buffer[0] = '#';
+ Q_strncpy(buffer + 1, text, bufferSize - 1);
+ buffer[bufferSize-1] = 0;
+ }
+ else
+ {
+ GetText(buffer, bufferSize);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: unlocalized text symbol
+//-----------------------------------------------------------------------------
+StringIndex_t TextImage::GetUnlocalizedTextSymbol()
+{
+ return _unlocalizedTextSymbol;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes the current font
+//-----------------------------------------------------------------------------
+void TextImage::SetFont(HFont font)
+{
+ _font = font;
+ m_bRecalculateTruncation = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the font of the text.
+//-----------------------------------------------------------------------------
+HFont TextImage::GetFont()
+{
+ if ( m_bRenderUsingFallbackFont )
+ {
+ return _fallbackFont;
+ }
+
+ return _font;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the size of the TextImage. This is directly tied to drawWidth
+//-----------------------------------------------------------------------------
+void TextImage::SetSize(int wide, int tall)
+{
+ Image::SetSize(wide, tall);
+ _drawWidth = wide;
+ m_bRecalculateTruncation = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw the Image on screen.
+//-----------------------------------------------------------------------------
+void TextImage::Paint()
+{
+ int wide, tall;
+ GetSize(wide, tall);
+
+ if (!_utext || GetFont() == INVALID_FONT )
+ return;
+
+ if (m_bRecalculateTruncation)
+ {
+ if ( m_bWrap || m_bWrapCenter )
+ {
+ RecalculateNewLinePositions();
+ }
+
+ RecalculateEllipsesPosition();
+ }
+
+ DrawSetTextColor(GetColor());
+ HFont font = GetFont();
+ DrawSetTextFont(font);
+
+ int lineHeight = surface()->GetFontTall(font);
+ float x = 0.0f;
+ int y = 0;
+ int iIndent = 0;
+ int iNextColorChange = 0;
+
+ int px, py;
+ GetPos(px, py);
+
+ int currentLineBreak = 0;
+
+ if ( m_bWrapCenter && m_LineXIndent.Count() )
+ {
+ x = m_LineXIndent[0];
+ }
+
+ for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
+ {
+ wchar_t ch = wsz[0];
+
+ if ( m_bAllCaps )
+ {
+ ch = towupper( ch );
+ }
+
+ if ( m_ColorChangeStream.Count() > iNextColorChange )
+ {
+ if ( m_ColorChangeStream[iNextColorChange].textStreamIndex == (wsz - _utext) )
+ {
+ DrawSetTextColor( m_ColorChangeStream[iNextColorChange].color );
+ iNextColorChange++;
+ }
+ }
+
+ // check for special characters
+ if ( ch == '\r' || ch <= 8 )
+ {
+ // ignore, just use \n for newlines
+ continue;
+ }
+ else if (ch == '\n')
+ {
+ // newline
+ iIndent++;
+ if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() )
+ {
+ x = m_LineXIndent[iIndent];
+ }
+ else
+ {
+ x = 0;
+ }
+ y += lineHeight;
+ continue;
+ }
+ else if (ch == '&')
+ {
+ // "&&" means draw a single ampersand, single one is a shortcut character
+ if (wsz[1] == '&')
+ {
+ // just move on and draw the second ampersand
+ wsz++;
+ }
+ else
+ {
+ // draw the underline, then continue to the next character without moving forward
+#ifdef VGUI_DRAW_HOTKEYS_ENABLED
+ surface()->DrawSetTextPos(x + px, y + py);
+ surface()->DrawUnicodeChar('_');
+#endif
+ continue;
+ }
+ }
+
+ // see if we've hit the truncated portion of the string
+ if (wsz == m_pwszEllipsesPosition)
+ {
+ // string is truncated, draw ellipses
+ for (int i = 0; i < 3; i++)
+ {
+ surface()->DrawSetTextPos(x + px, y + py);
+ surface()->DrawUnicodeChar('.');
+ x += surface()->GetCharacterWidth(font, '.');
+ }
+ break;
+ }
+
+ if (currentLineBreak != m_LineBreaks.Count())
+ {
+ if (wsz == m_LineBreaks[currentLineBreak])
+ {
+ // newline
+ iIndent++;
+ if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() )
+ {
+ x = m_LineXIndent[iIndent];
+ }
+ else
+ {
+ x = 0;
+ }
+
+ y += lineHeight;
+ currentLineBreak++;
+ }
+ }
+
+ // Underlined text wants to draw the spaces anyway
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( wsz > _utext )
+ chBefore = wsz[-1];
+ chAfter = wsz[1];
+ float flWide = 0.0f, flabcA = 0.0f;
+ surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
+ if ( ch == L' ' )
+ x = ceil( x );
+
+ surface()->DrawSetTextPos( x + px, y + py);
+ surface()->DrawUnicodeChar(ch);
+ x += floor(flWide + 0.6);
+#else
+ surface()->DrawSetTextPos( x + px, y + py);
+ surface()->DrawUnicodeChar(ch);
+ x += surface()->GetCharacterWidth(font, ch);
+#endif
+ }
+
+ // Useful debugging
+ /*
+ DrawSetColor(GetColor());
+ DrawOutlinedRect( 0,0, _drawWidth, tall );
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the size of a text string in pixels
+//-----------------------------------------------------------------------------
+void TextImage::GetTextSize(int &wide, int &tall)
+{
+ wide = 0;
+ tall = 0;
+ int maxWide = 0;
+ const wchar_t *text = _utext;
+
+ HFont font = _font;
+ if ( font == INVALID_FONT )
+ return;
+
+ if ( m_bWrap || m_bWrapCenter )
+ {
+ RecalculateNewLinePositions();
+ }
+
+ // For height, use the remapped font
+ int fontHeight = surface()->GetFontTall(GetFont());
+ tall = fontHeight;
+
+ int textLen = wcslen(text);
+ for (int i = 0; i < textLen; i++)
+ {
+ wchar_t ch = text[i];
+
+ // handle stupid special characters, these should be removed
+ if ( ch == '&' )
+ {
+ continue;
+ }
+
+ if ( m_bAllCaps )
+ {
+ ch = towupper( ch );
+ }
+
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( i > 0 )
+ chBefore = text[i-1];
+ chAfter = text[i+1];
+ float flWide = 0.0f, flabcA;
+ surface()->GetKernedCharWidth( font, text[i], chBefore, chAfter, flWide, flabcA );
+ if ( text[i] == L' ' )
+ flWide = ceil( flWide );
+ wide += floor( flWide + 0.6);
+#else
+ int a, b, c;
+ surface()->GetCharABCwide(font, ch, a, b, c);
+ wide += (a + b + c);
+#endif
+
+
+ if (ch == '\n')
+ {
+ tall += fontHeight;
+ if(wide>maxWide)
+ {
+ maxWide=wide;
+ }
+ wide=0; // new line, wide is reset...
+ }
+
+ if ( m_bWrap || m_bWrapCenter )
+ {
+ for(int j=0; j<m_LineBreaks.Count(); j++)
+ {
+ if ( &text[i] == m_LineBreaks[j] )
+ {
+ tall += fontHeight;
+ if(wide>maxWide)
+ {
+ maxWide=wide;
+ }
+ wide=0; // new line, wide is reset...
+ }
+ }
+ }
+
+ }
+#ifdef OSX
+ wide += 2;
+ if ( textLen < 3 )
+ wide += 3;
+#endif
+ if (wide < maxWide)
+ {
+ // maxWide only gets set if a newline is in the label
+ wide = maxWide;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the size of the text in the image
+//-----------------------------------------------------------------------------
+void TextImage::GetContentSize(int &wide, int &tall)
+{
+ GetTextSize(wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resize the text image to the content size
+//-----------------------------------------------------------------------------
+void TextImage::ResizeImageToContent()
+{
+ int wide, tall;
+ GetContentSize(wide, tall);
+ SetSize(wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Recalculates line breaks
+//-----------------------------------------------------------------------------
+void TextImage::RecalculateNewLinePositions()
+{
+ HFont font = GetFont();
+
+ int charWidth;
+ int x = 0;
+
+ //int wordStartIndex = 0;
+ wchar_t *wordStartIndex = _utext;
+ int wordLength = 0;
+ bool hasWord = false;
+ bool justStartedNewLine = true;
+ bool wordStartedOnNewLine = true;
+
+ int startChar = 0;
+
+ // clear the line breaks list
+ m_LineBreaks.RemoveAll();
+ m_LineXIndent.RemoveAll();
+
+ // handle the case where this char is a new line, in that case
+ // we have already taken its break index into account above so skip it.
+ if (_utext[startChar] == '\r' || _utext[startChar] == '\n')
+ {
+ startChar++;
+ }
+
+ // loop through all the characters
+ for (wchar_t *wsz = &_utext[startChar]; *wsz != 0; wsz++)
+ {
+ // handle stupid special characters, these should be removed
+ // 0x01, 0x02 and 0x03 are color escape characters and should be ignored
+ if ( ( wsz[0] == '&' || wsz[0] == 0x01 || wsz[0] == 0x02 || wsz[0] == 0x03 ) && wsz[1] != 0 )
+ {
+ wsz++;
+ }
+
+ wchar_t ch = wsz[0];
+
+ if ( m_bAllCaps )
+ {
+ ch = towupper( ch );
+ }
+
+ // line break only on whitespace characters
+ if (!iswspace(ch))
+ {
+ if ( !hasWord )
+ {
+ // Start a new word
+ wordStartIndex = wsz;
+ hasWord = true;
+ wordStartedOnNewLine = justStartedNewLine;
+ wordLength = 0;
+ }
+ //else append to the current word
+ }
+ else
+ {
+ // whitespace/punctuation character
+ // end the word
+ hasWord = false;
+ }
+
+ // get the width
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( wsz > _utext )
+ chBefore = wsz[-1];
+ chAfter = wsz[1];
+ float flWide = 0.0f, flabcA = 0.0f;
+ surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
+ charWidth = floor( flWide + 0.6 );
+#else
+ charWidth = surface()->GetCharacterWidth(font, ch);
+#endif
+ if (!iswcntrl(ch))
+ {
+ justStartedNewLine = false;
+ }
+
+ // check to see if the word is past the end of the line [wordStartIndex, i)
+ if ((x + charWidth) > _drawWidth || ch == '\r' || ch == '\n')
+ {
+ justStartedNewLine = true;
+ hasWord = false;
+
+ if (ch == '\r' || ch == '\n')
+ {
+ // set the break at the current character
+ //don't do this, paint will manually wrap on newline chars
+ // m_LineBreaks.AddToTail(i);
+ }
+ else if (wordStartedOnNewLine)
+ {
+ // word is longer than a line, so set the break at the current cursor
+ m_LineBreaks.AddToTail(wsz);
+ }
+ else
+ {
+ // set it at the last word Start
+ m_LineBreaks.AddToTail(wordStartIndex);
+
+ // just back to reparse the next line of text
+ // ywb 8/1/07: Back off one extra char since the 'continue' will increment wsz for us by one in the for loop
+ wsz = wordStartIndex - 1;
+ }
+
+ // reset word length
+ wordLength = 0;
+ x = 0;
+ continue;
+ }
+
+ // add to the size
+ x += charWidth;
+ wordLength += charWidth;
+ }
+
+ RecalculateCenterWrapIndents();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculates where the text should be truncated
+//-----------------------------------------------------------------------------
+void TextImage::RecalculateEllipsesPosition()
+{
+ m_bRecalculateTruncation = false;
+ m_pwszEllipsesPosition = NULL;
+
+ //don't insert ellipses on wrapped strings
+ if ( m_bWrap || m_bWrapCenter )
+ return;
+
+ // don't truncate strings with newlines
+ if (wcschr(_utext, '\n') != NULL)
+ return;
+
+ if ( _drawWidth == 0 )
+ {
+ int h;
+ GetSize( _drawWidth, h );
+ }
+
+ for ( int check = 0; check < (m_bUseFallbackFont ? 2 : 1); ++check )
+ {
+ HFont font = GetFont();
+ if ( check == 1 && _fallbackFont != INVALID_FONT )
+ {
+ m_pwszEllipsesPosition = NULL;
+ font = _fallbackFont;
+ m_bRenderUsingFallbackFont = true;
+ }
+
+ int ellipsesWidth = 3 * surface()->GetCharacterWidth(font, '.');
+ int x = 0;
+
+ for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
+ {
+ wchar_t ch = wsz[0];
+
+ if ( m_bAllCaps )
+ {
+ ch = towupper( ch );
+ }
+
+ // check for special characters
+ if (ch == '\r')
+ {
+ // ignore, just use \n for newlines
+ continue;
+ }
+ else if (ch == '&')
+ {
+ // "&&" means draw a single ampersand, single one is a shortcut character
+ if (wsz[1] == '&')
+ {
+ // just move on and draw the second ampersand
+ wsz++;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( wsz > _utext )
+ chBefore = wsz[-1];
+ chAfter = wsz[1];
+ float flWide = 0.0f, flabcA = 0.0f;
+ surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
+ int len = floor( flWide + 0.6 );
+#else
+ int len = surface()->GetCharacterWidth(font, ch);
+#endif
+
+ // don't truncate the first character
+ if (wsz == _utext)
+ {
+ x += len;
+ continue;
+ }
+
+ if (x + len + ellipsesWidth > _drawWidth)
+ {
+ // potential have an ellipses, see if the remaining characters will fit
+ int remainingLength = len;
+ for (const wchar_t *rwsz = wsz + 1; *rwsz != 0; rwsz++)
+ {
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( rwsz > _utext )
+ chBefore = rwsz[-1];
+ chAfter = rwsz[1];
+ float flWide = 0.0f, flabcA = 0.0f;
+ surface()->GetKernedCharWidth( font, *rwsz, chBefore, chAfter, flWide, flabcA );
+ int len = floor( flWide + 0.6 );
+ remainingLength += floor( flWide + 0.6 );
+#else
+ remainingLength += surface()->GetCharacterWidth(font, *rwsz);
+#endif
+ }
+
+ if (x + remainingLength > _drawWidth)
+ {
+ // looks like we've got an ellipses situation
+ m_pwszEllipsesPosition = wsz;
+ break;
+ }
+ }
+
+ x += len;
+ }
+
+ // Didn't need ellipses...
+ if ( !m_pwszEllipsesPosition )
+ break;
+ }
+}
+
+void TextImage::SetWrap( bool bWrap )
+{
+ m_bWrap = bWrap;
+}
+
+void TextImage::SetCenterWrap( bool bWrap )
+{
+ m_bWrapCenter = bWrap;
+}
+
+
+void TextImage::SetUseFallbackFont( bool bState, HFont hFallback )
+{
+ m_bUseFallbackFont = bState;
+ _fallbackFont = hFallback;
+}
+
+void TextImage::SetAllCaps( bool bAllCaps )
+{
+ m_bAllCaps = bAllCaps;
+}
+
+void TextImage::ResizeImageToContentMaxWidth( int nMaxWidth )
+{
+ _drawWidth = nMaxWidth;
+ // Since we might have to use the "fallback" font, go ahead and recalc the ellipses state first to see if that's the case
+ // NOTE: I think there may be a race condition lurking here, but this seems to work.
+ if ( m_bRecalculateTruncation )
+ {
+ if ( m_bWrap || m_bWrapCenter )
+ {
+ RecalculateNewLinePositions();
+ }
+
+ RecalculateEllipsesPosition();
+ }
+
+ ResizeImageToContent();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: For center wrapping of multi-line text images, determines the indent each line needs to be centered
+//-----------------------------------------------------------------------------
+void TextImage::RecalculateCenterWrapIndents()
+{
+ m_LineXIndent.RemoveAll();
+
+ if ( !m_bWrapCenter )
+ return;
+
+ if (!_utext || GetFont() == INVALID_FONT )
+ return;
+
+ HFont font = GetFont();
+ int px, py;
+ GetPos(px, py);
+
+ int currentLineBreak = 0;
+ int iCurLineW = 0;
+
+ for (wchar_t *wsz = _utext; *wsz != 0; wsz++)
+ {
+ wchar_t ch = wsz[0];
+
+ if ( m_bAllCaps )
+ {
+ ch = towupper( ch );
+ }
+
+ // check for special characters
+ if (ch == '\r')
+ {
+ // ignore, just use \n for newlines
+ continue;
+ }
+ else if (ch == '\n')
+ {
+ int iIdx = m_LineXIndent.AddToTail();
+ m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
+
+ iCurLineW = 0;
+ continue;
+ }
+ else if (ch == '&')
+ {
+ // "&&" means draw a single ampersand, single one is a shortcut character
+ if (wsz[1] == '&')
+ {
+ // just move on and draw the second ampersand
+ wsz++;
+ }
+ else
+ {
+ // draw the underline, then continue to the next character without moving forward
+ continue;
+ }
+ }
+
+ // Don't need to check ellipses, they're not used when wrapping
+
+ if (currentLineBreak != m_LineBreaks.Count())
+ {
+ if (wsz == m_LineBreaks[currentLineBreak])
+ {
+ int iIdx = m_LineXIndent.AddToTail();
+ m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
+
+ iCurLineW = 0;
+ currentLineBreak++;
+ }
+ }
+
+#if USE_GETKERNEDCHARWIDTH
+ wchar_t chBefore = 0;
+ wchar_t chAfter = 0;
+ if ( wsz > _utext )
+ chBefore = wsz[-1];
+ chAfter = wsz[1];
+ float flWide = 0.0f, flabcA = 0.0f;
+ surface()->GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA );
+ iCurLineW += floor( flWide + 0.6 );
+#else
+ iCurLineW += surface()->GetCharacterWidth(font, ch);
+#endif
+ }
+
+ // Add the final line
+ int iIdx = m_LineXIndent.AddToTail();
+ m_LineXIndent[iIdx] = (_drawWidth - iCurLineW) * 0.5;
+}
+
+void TextImage::AddColorChange( Color col, int iTextStreamIndex )
+{
+ label_colorchange_t tmpChange;
+ tmpChange.color = col;
+ tmpChange.textStreamIndex = iTextStreamIndex;
+ m_ColorChangeStream.Insert( tmpChange );
+}
+
+void TextImage::SetColorChangeStream( CUtlSortVector<label_colorchange_t,CColorChangeListLess> *pUtlVecStream )
+{
+ ClearColorChangeStream();
+
+ m_ColorChangeStream = *pUtlVecStream;
+}