|
|
|
|
@@ -82,90 +82,39 @@ Text* Text::New( Font* font, unsigned int characterSize ) {
|
|
|
|
|
return eeNew( Text, ( font, characterSize ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Text::Text() :
|
|
|
|
|
mString(),
|
|
|
|
|
mFont( NULL ),
|
|
|
|
|
mFontSize( 12 ),
|
|
|
|
|
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
|
|
|
|
|
mStyle( Regular ),
|
|
|
|
|
mFillColor( 255, 255, 255, 255 ),
|
|
|
|
|
mOutlineColor( 0, 0, 0, 255 ),
|
|
|
|
|
mOutlineThickness( 0 ),
|
|
|
|
|
mGeometryNeedUpdate( false ),
|
|
|
|
|
mCachedWidthNeedUpdate( false ),
|
|
|
|
|
mColorsNeedUpdate( false ),
|
|
|
|
|
mCachedWidth( 0 ),
|
|
|
|
|
mNumLines( 0 ),
|
|
|
|
|
mLargestLineCharCount( 0 ),
|
|
|
|
|
mShadowColor( Color( 0, 0, 0, 255 ) ),
|
|
|
|
|
mAlign( TEXT_ALIGN_LEFT ),
|
|
|
|
|
mFontHeight( 0 ),
|
|
|
|
|
mTabWidth( 4 ) {}
|
|
|
|
|
Text::Text() {}
|
|
|
|
|
|
|
|
|
|
Text::Text( const String& string, Font* font, unsigned int characterSize ) :
|
|
|
|
|
mString( string ),
|
|
|
|
|
mFont( font ),
|
|
|
|
|
mFontSize( characterSize ),
|
|
|
|
|
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
|
|
|
|
|
mStyle( Regular ),
|
|
|
|
|
mFillColor( 255, 255, 255, 255 ),
|
|
|
|
|
mOutlineColor( 0, 0, 0, 255 ),
|
|
|
|
|
mOutlineThickness( 0 ),
|
|
|
|
|
mGeometryNeedUpdate( true ),
|
|
|
|
|
mCachedWidthNeedUpdate( true ),
|
|
|
|
|
mColorsNeedUpdate( true ),
|
|
|
|
|
mCachedWidth( 0 ),
|
|
|
|
|
mNumLines( 0 ),
|
|
|
|
|
mLargestLineCharCount( 0 ),
|
|
|
|
|
mShadowColor( Color( 0, 0, 0, 255 ) ),
|
|
|
|
|
mAlign( TEXT_ALIGN_LEFT ),
|
|
|
|
|
mFontHeight( mFont->getFontHeight( mRealFontSize ) ),
|
|
|
|
|
mTabWidth( 4 ) {
|
|
|
|
|
if ( !mFont->isScalable() ) {
|
|
|
|
|
mFontSize = mFontHeight;
|
|
|
|
|
mRealFontSize = mFontHeight;
|
|
|
|
|
}
|
|
|
|
|
Text( font, characterSize ) {
|
|
|
|
|
mString = string;
|
|
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Text::Text( Font* font, unsigned int characterSize ) :
|
|
|
|
|
mFont( font ),
|
|
|
|
|
mFontSize( characterSize ),
|
|
|
|
|
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
|
|
|
|
|
mStyle( Regular ),
|
|
|
|
|
mFillColor( 255, 255, 255, 255 ),
|
|
|
|
|
mOutlineColor( 0, 0, 0, 255 ),
|
|
|
|
|
mOutlineThickness( 0 ),
|
|
|
|
|
mGeometryNeedUpdate( true ),
|
|
|
|
|
mCachedWidthNeedUpdate( true ),
|
|
|
|
|
mColorsNeedUpdate( true ),
|
|
|
|
|
mCachedWidth( 0 ),
|
|
|
|
|
mNumLines( 0 ),
|
|
|
|
|
mLargestLineCharCount( 0 ),
|
|
|
|
|
mShadowColor( Color( 0, 0, 0, 255 ) ),
|
|
|
|
|
mAlign( TEXT_ALIGN_LEFT ),
|
|
|
|
|
mFontHeight( mFont->getFontHeight( mRealFontSize ) ),
|
|
|
|
|
mTabWidth( 4 ) {
|
|
|
|
|
if ( !mFont->isScalable() ) {
|
|
|
|
|
mFontSize = mFontHeight;
|
|
|
|
|
mRealFontSize( PixelDensity::dpToPxI( characterSize ) ) {
|
|
|
|
|
mFontStyleConfig.Font = font;
|
|
|
|
|
mFontStyleConfig.CharacterSize = characterSize;
|
|
|
|
|
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFontStyleConfig.Font->isScalable() ) {
|
|
|
|
|
mFontStyleConfig.CharacterSize = mFontHeight;
|
|
|
|
|
mRealFontSize = mFontHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::create( Font* font, const String& text, Color FontColor, Color FontShadowColor,
|
|
|
|
|
Uint32 characterSize ) {
|
|
|
|
|
mFont = font;
|
|
|
|
|
mFontStyleConfig.Font = font;
|
|
|
|
|
mFontStyleConfig.CharacterSize = characterSize;
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( characterSize );
|
|
|
|
|
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFontStyleConfig.Font->isScalable() ) {
|
|
|
|
|
mFontStyleConfig.CharacterSize = mFontHeight;
|
|
|
|
|
mRealFontSize = mFontHeight;
|
|
|
|
|
}
|
|
|
|
|
mString = text;
|
|
|
|
|
mFontSize = characterSize;
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
|
|
|
|
|
Float dp = PixelDensity::dpToPx( 1 );
|
|
|
|
|
mShadowOffset = { dp, dp };
|
|
|
|
|
setFillColor( FontColor );
|
|
|
|
|
setShadowColor( FontShadowColor );
|
|
|
|
|
mGeometryNeedUpdate = true;
|
|
|
|
|
mCachedWidthNeedUpdate = true;
|
|
|
|
|
mColorsNeedUpdate = true;
|
|
|
|
|
ensureColorUpdate();
|
|
|
|
|
ensureGeometryUpdate();
|
|
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setString( const String& string ) {
|
|
|
|
|
@@ -176,8 +125,8 @@ void Text::setString( const String& string ) {
|
|
|
|
|
mCachedWidthNeedUpdate = true;
|
|
|
|
|
mContainsColorEmoji = false;
|
|
|
|
|
if ( FontManager::instance()->getColorEmojiFont() != nullptr ) {
|
|
|
|
|
if ( mFont->getType() == FontType::TTF ) {
|
|
|
|
|
FontTrueType* fontTrueType = static_cast<FontTrueType*>( mFont );
|
|
|
|
|
if ( mFontStyleConfig.Font->getType() == FontType::TTF ) {
|
|
|
|
|
FontTrueType* fontTrueType = static_cast<FontTrueType*>( mFontStyleConfig.Font );
|
|
|
|
|
if ( fontTrueType->isColorEmojiFont() || !fontTrueType->isEmojiFont() )
|
|
|
|
|
mContainsColorEmoji = Font::containsEmojiCodePoint( string );
|
|
|
|
|
}
|
|
|
|
|
@@ -186,13 +135,13 @@ void Text::setString( const String& string ) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setFont( Font* font ) {
|
|
|
|
|
if ( NULL != font && mFont != font ) {
|
|
|
|
|
mFont = font;
|
|
|
|
|
if ( NULL != font && mFontStyleConfig.Font != font ) {
|
|
|
|
|
mFontStyleConfig.Font = font;
|
|
|
|
|
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
|
|
|
|
|
mFontHeight = mFont->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFont->isScalable() ) {
|
|
|
|
|
mFontSize = mFontHeight;
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize );
|
|
|
|
|
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFontStyleConfig.Font->isScalable() ) {
|
|
|
|
|
mFontStyleConfig.CharacterSize = mFontHeight;
|
|
|
|
|
mRealFontSize = mFontHeight;
|
|
|
|
|
}
|
|
|
|
|
mGeometryNeedUpdate = true;
|
|
|
|
|
@@ -201,13 +150,13 @@ void Text::setFont( Font* font ) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setFontSize( unsigned int size ) {
|
|
|
|
|
if ( NULL != mFont && mFontSize != size ) {
|
|
|
|
|
mFontSize = size;
|
|
|
|
|
if ( NULL != mFontStyleConfig.Font && mFontStyleConfig.CharacterSize != size ) {
|
|
|
|
|
mFontStyleConfig.CharacterSize = size;
|
|
|
|
|
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
|
|
|
|
|
mFontHeight = mFont->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFont->isScalable() ) {
|
|
|
|
|
mFontSize = mFontHeight;
|
|
|
|
|
mRealFontSize = PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize );
|
|
|
|
|
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
|
|
|
|
|
if ( !mFontStyleConfig.Font->isScalable() ) {
|
|
|
|
|
mFontStyleConfig.CharacterSize = mFontHeight;
|
|
|
|
|
mRealFontSize = mFontHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -217,8 +166,8 @@ void Text::setFontSize( unsigned int size ) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setStyle( Uint32 style ) {
|
|
|
|
|
if ( mStyle != style ) {
|
|
|
|
|
mStyle = style;
|
|
|
|
|
if ( mFontStyleConfig.Style != style ) {
|
|
|
|
|
mFontStyleConfig.Style = style;
|
|
|
|
|
mColorsNeedUpdate = true;
|
|
|
|
|
mGeometryNeedUpdate = true;
|
|
|
|
|
mCachedWidthNeedUpdate = true;
|
|
|
|
|
@@ -230,22 +179,22 @@ void Text::setColor( const Color& color ) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setFillColor( const Color& color ) {
|
|
|
|
|
if ( color != mFillColor ) {
|
|
|
|
|
mFillColor = color;
|
|
|
|
|
if ( color != mFontStyleConfig.FontColor ) {
|
|
|
|
|
mFontStyleConfig.FontColor = color;
|
|
|
|
|
mColorsNeedUpdate = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setOutlineColor( const Color& color ) {
|
|
|
|
|
if ( color != mOutlineColor ) {
|
|
|
|
|
mOutlineColor = color;
|
|
|
|
|
if ( color != mFontStyleConfig.OutlineColor ) {
|
|
|
|
|
mFontStyleConfig.OutlineColor = color;
|
|
|
|
|
mColorsNeedUpdate = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setOutlineThickness( Float thickness ) {
|
|
|
|
|
if ( thickness != mOutlineThickness ) {
|
|
|
|
|
mOutlineThickness = thickness;
|
|
|
|
|
if ( thickness != mFontStyleConfig.OutlineThickness ) {
|
|
|
|
|
mFontStyleConfig.OutlineThickness = thickness;
|
|
|
|
|
mColorsNeedUpdate = true;
|
|
|
|
|
mGeometryNeedUpdate = true;
|
|
|
|
|
mCachedWidthNeedUpdate = true;
|
|
|
|
|
@@ -273,11 +222,11 @@ String& Text::getString() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Font* Text::getFont() const {
|
|
|
|
|
return mFont;
|
|
|
|
|
return mFontStyleConfig.Font;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int Text::getCharacterSize() const {
|
|
|
|
|
return mFontSize;
|
|
|
|
|
return mFontStyleConfig.CharacterSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int Text::getCharacterSizePx() const {
|
|
|
|
|
@@ -289,7 +238,7 @@ const Uint32& Text::getFontHeight() const {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint32 Text::getStyle() const {
|
|
|
|
|
return mStyle;
|
|
|
|
|
return mFontStyleConfig.Style;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setAlpha( const Uint8& alpha ) {
|
|
|
|
|
@@ -297,11 +246,11 @@ void Text::setAlpha( const Uint8& alpha ) {
|
|
|
|
|
for ( Uint32 i = 0; i < s; i++ ) {
|
|
|
|
|
mColors[i].a = alpha;
|
|
|
|
|
}
|
|
|
|
|
mFillColor.a = alpha;
|
|
|
|
|
mFontStyleConfig.FontColor.a = alpha;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Color& Text::getFillColor() const {
|
|
|
|
|
return mFillColor;
|
|
|
|
|
return mFontStyleConfig.FontColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Color& Text::getColor() const {
|
|
|
|
|
@@ -309,70 +258,34 @@ const Color& Text::getColor() const {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Color& Text::getOutlineColor() const {
|
|
|
|
|
return mOutlineColor;
|
|
|
|
|
return mFontStyleConfig.OutlineColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Float Text::getOutlineThickness() const {
|
|
|
|
|
return mOutlineThickness;
|
|
|
|
|
return mFontStyleConfig.OutlineThickness;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector2f Text::findCharacterPos( std::size_t index ) const {
|
|
|
|
|
// Make sure that we have a valid font
|
|
|
|
|
if ( !mFont || mString.empty() )
|
|
|
|
|
if ( !mFontStyleConfig.Font || mString.empty() )
|
|
|
|
|
return Vector2f();
|
|
|
|
|
|
|
|
|
|
// Adjust the index if it's out of range
|
|
|
|
|
if ( index > mString.size() )
|
|
|
|
|
index = mString.size();
|
|
|
|
|
|
|
|
|
|
const_cast<Text*>( this )->ensureGeometryUpdate();
|
|
|
|
|
|
|
|
|
|
return Vector2f( mGlyphCache[index].Left, mGlyphCache[index].Top );
|
|
|
|
|
return Text::findCharacterPos( index, mFontStyleConfig.Font, mRealFontSize, mString,
|
|
|
|
|
mFontStyleConfig.Style, mTabWidth,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Int32 Text::findCharacterFromPos( const Vector2i& pos, bool ) const {
|
|
|
|
|
if ( NULL == mFont || mString.empty() )
|
|
|
|
|
Int32 Text::findCharacterFromPos( const Vector2i& pos, bool nearest ) const {
|
|
|
|
|
if ( NULL == mFontStyleConfig.Font || mString.empty() )
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const_cast<Text*>( this )->ensureGeometryUpdate();
|
|
|
|
|
|
|
|
|
|
if ( mLinesStartIndex.empty() )
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
Vector2f charCenter;
|
|
|
|
|
Int32 nearest = 0;
|
|
|
|
|
Int32 minDist = std::numeric_limits<Int32>::max();
|
|
|
|
|
Int32 curDist = -1;
|
|
|
|
|
Vector2f fpos( pos.asFloat() );
|
|
|
|
|
|
|
|
|
|
Float textHeight = mFont->getLineSpacing( mRealFontSize );
|
|
|
|
|
Int32 approximateSearchLine = static_cast<Int32>( eefloor( pos.y / textHeight ) );
|
|
|
|
|
approximateSearchLine = eemin(
|
|
|
|
|
eemax( 0, approximateSearchLine ),
|
|
|
|
|
static_cast<Int32>( mLinesStartIndex.size() > 1 ? mLinesStartIndex.size() : 1 ) - 1 );
|
|
|
|
|
size_t start = mLinesStartIndex[approximateSearchLine];
|
|
|
|
|
size_t end = approximateSearchLine == static_cast<Int32>( mLinesStartIndex.size() ) - 1
|
|
|
|
|
? mString.size()
|
|
|
|
|
: mLinesStartIndex[approximateSearchLine + 1];
|
|
|
|
|
|
|
|
|
|
if ( mString[start] == '\n' && start + 1 < mString.size() ) {
|
|
|
|
|
start++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( end >= mGlyphCache.size() )
|
|
|
|
|
end = mGlyphCache.size() - 1;
|
|
|
|
|
|
|
|
|
|
for ( std::size_t i = start; i <= end; ++i ) {
|
|
|
|
|
charCenter.x = mGlyphCache[i].Left;
|
|
|
|
|
charCenter.y = mGlyphCache[i].Top + mGlyphCache[i].getHeight();
|
|
|
|
|
curDist = eeabs( fpos.distance( charCenter ) );
|
|
|
|
|
if ( curDist < minDist ) {
|
|
|
|
|
nearest = i;
|
|
|
|
|
minDist = curDist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nearest;
|
|
|
|
|
return Text::findCharacterFromPos( pos, nearest, mFontStyleConfig.Font, mRealFontSize, mString,
|
|
|
|
|
mFontStyleConfig.Style, mTabWidth,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isStopSelChar( Uint32 c ) {
|
|
|
|
|
@@ -429,14 +342,15 @@ Float Text::getTextWidth( Font* font, const Uint32& fontSize, const String& stri
|
|
|
|
|
Glyph glyph = font->getGlyph( rune, fontSize, bold, italic, outlineThickness );
|
|
|
|
|
if ( rune != '\r' && rune != '\t' ) {
|
|
|
|
|
width += font->getKerning( prevChar, rune, fontSize, bold, italic, outlineThickness );
|
|
|
|
|
prevChar = rune;
|
|
|
|
|
width += glyph.advance;
|
|
|
|
|
} else if ( rune == '\t' ) {
|
|
|
|
|
width += hspace * tabWidth;
|
|
|
|
|
} else if ( rune == '\n' ) {
|
|
|
|
|
}
|
|
|
|
|
if ( rune == '\n' ) {
|
|
|
|
|
width = 0;
|
|
|
|
|
}
|
|
|
|
|
maxWidth = eemax( width, maxWidth );
|
|
|
|
|
prevChar = rune;
|
|
|
|
|
}
|
|
|
|
|
return maxWidth;
|
|
|
|
|
}
|
|
|
|
|
@@ -527,7 +441,8 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
|
|
|
|
|
width += glyph.advance;
|
|
|
|
|
} else if ( rune == '\t' ) {
|
|
|
|
|
width += hspace * tabWidth;
|
|
|
|
|
} else if ( rune == '\n' ) {
|
|
|
|
|
}
|
|
|
|
|
if ( rune == '\n' ) {
|
|
|
|
|
lWidth = 0;
|
|
|
|
|
width = 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -565,72 +480,55 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
|
|
|
|
|
return nearest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::getWidthInfo() {
|
|
|
|
|
if ( NULL == mFont || mString.empty() )
|
|
|
|
|
void Text::updateWidthCache() {
|
|
|
|
|
if ( NULL == mFontStyleConfig.Font || mString.empty() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mLinesWidth.clear();
|
|
|
|
|
mLinesStartIndex.clear();
|
|
|
|
|
|
|
|
|
|
Float Width = 0, MaxWidth = 0;
|
|
|
|
|
Uint32 CharID;
|
|
|
|
|
Int32 Lines = 1;
|
|
|
|
|
Int32 CharCount = 0;
|
|
|
|
|
Float width = 0;
|
|
|
|
|
Float maxWidth = 0;
|
|
|
|
|
Uint32 rune;
|
|
|
|
|
Uint32 prevChar = 0;
|
|
|
|
|
mLargestLineCharCount = 0;
|
|
|
|
|
bool bold = ( mStyle & Bold ) != 0;
|
|
|
|
|
bool italic = ( mStyle & Italic ) != 0;
|
|
|
|
|
|
|
|
|
|
mLinesStartIndex.push_back( 0 );
|
|
|
|
|
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
|
|
|
|
|
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
|
|
|
|
|
|
|
|
|
|
Float hspace = static_cast<Float>(
|
|
|
|
|
mFont->getGlyph( L' ', mRealFontSize, bold, italic, mOutlineThickness ).advance );
|
|
|
|
|
mFontStyleConfig.Font
|
|
|
|
|
->getGlyph( L' ', mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness )
|
|
|
|
|
.advance );
|
|
|
|
|
|
|
|
|
|
for ( std::size_t i = 0; i < mString.size(); ++i ) {
|
|
|
|
|
CharID = static_cast<Int32>( mString.at( i ) );
|
|
|
|
|
const Glyph& glyph =
|
|
|
|
|
mFont->getGlyph( CharID, mRealFontSize, bold, italic, mOutlineThickness );
|
|
|
|
|
|
|
|
|
|
if ( CharID != '\r' && CharID != '\t' ) {
|
|
|
|
|
Width += mFont->getKerning( prevChar, CharID, mRealFontSize, bold, italic,
|
|
|
|
|
mOutlineThickness );
|
|
|
|
|
prevChar = CharID;
|
|
|
|
|
Width += glyph.advance;
|
|
|
|
|
size_t size = mString.size();
|
|
|
|
|
for ( std::size_t i = 0; i < size; ++i ) {
|
|
|
|
|
rune = mString[i];
|
|
|
|
|
const Glyph& glyph = mFontStyleConfig.Font->getGlyph( rune, mRealFontSize, bold, italic,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
if ( rune != '\r' && rune != '\t' ) {
|
|
|
|
|
width += mFontStyleConfig.Font->getKerning( prevChar, rune, mRealFontSize, bold, italic,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
width += glyph.advance;
|
|
|
|
|
} else if ( rune == '\t' ) {
|
|
|
|
|
width += hspace * mTabWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CharCount++;
|
|
|
|
|
|
|
|
|
|
if ( CharID == '\t' ) {
|
|
|
|
|
Width += hspace * mTabWidth;
|
|
|
|
|
}
|
|
|
|
|
if ( CharID == '\n' ) {
|
|
|
|
|
mLinesStartIndex.push_back( i );
|
|
|
|
|
Lines++;
|
|
|
|
|
|
|
|
|
|
mLinesWidth.push_back( Width - glyph.advance );
|
|
|
|
|
|
|
|
|
|
Width = 0;
|
|
|
|
|
|
|
|
|
|
CharCount = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if ( CharCount > mLargestLineCharCount )
|
|
|
|
|
mLargestLineCharCount = CharCount;
|
|
|
|
|
if ( rune == '\n' ) {
|
|
|
|
|
mLinesWidth.push_back( width - glyph.advance );
|
|
|
|
|
width = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( Width > MaxWidth )
|
|
|
|
|
MaxWidth = Width;
|
|
|
|
|
if ( width > maxWidth )
|
|
|
|
|
maxWidth = width;
|
|
|
|
|
prevChar = rune;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( mString.size() && mString.at( mString.size() - 1 ) != '\n' ) {
|
|
|
|
|
mLinesWidth.push_back( Width );
|
|
|
|
|
}
|
|
|
|
|
if ( !mString.empty() && mString[mString.size() - 1] != '\n' )
|
|
|
|
|
mLinesWidth.push_back( width );
|
|
|
|
|
|
|
|
|
|
mCachedWidth = MaxWidth;
|
|
|
|
|
mNumLines = Lines;
|
|
|
|
|
mCachedWidth = maxWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::wrapText( const Uint32& maxWidth ) {
|
|
|
|
|
if ( !mString.size() || NULL == mFont )
|
|
|
|
|
if ( !mString.size() || NULL == mFontStyleConfig.Font )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Float tCurWidth = 0.f;
|
|
|
|
|
@@ -639,14 +537,17 @@ void Text::wrapText( const Uint32& maxWidth ) {
|
|
|
|
|
String::StringBaseType* tChar = &mString[0];
|
|
|
|
|
String::StringBaseType* tLastSpace = NULL;
|
|
|
|
|
Uint32 prevChar = 0;
|
|
|
|
|
bool bold = ( mStyle & Bold ) != 0;
|
|
|
|
|
bool italic = ( mStyle & Italic ) != 0;
|
|
|
|
|
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
|
|
|
|
|
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
|
|
|
|
|
|
|
|
|
|
Float hspace = static_cast<Float>(
|
|
|
|
|
mFont->getGlyph( L' ', mRealFontSize, bold, italic, mOutlineThickness ).advance );
|
|
|
|
|
mFontStyleConfig.Font
|
|
|
|
|
->getGlyph( L' ', mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness )
|
|
|
|
|
.advance );
|
|
|
|
|
|
|
|
|
|
while ( *tChar ) {
|
|
|
|
|
Glyph pChar = mFont->getGlyph( *tChar, mRealFontSize, bold, italic, mOutlineThickness );
|
|
|
|
|
Glyph pChar = mFontStyleConfig.Font->getGlyph( *tChar, mRealFontSize, bold, italic,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
|
|
|
|
|
Float fCharWidth = (Float)pChar.advance;
|
|
|
|
|
|
|
|
|
|
@@ -659,8 +560,8 @@ void Text::wrapText( const Uint32& maxWidth ) {
|
|
|
|
|
tWordWidth += fCharWidth;
|
|
|
|
|
|
|
|
|
|
if ( *tChar != '\r' ) {
|
|
|
|
|
tWordWidth += mFont->getKerning( prevChar, *tChar, mRealFontSize, bold, italic,
|
|
|
|
|
mOutlineThickness );
|
|
|
|
|
tWordWidth += mFontStyleConfig.Font->getKerning(
|
|
|
|
|
prevChar, *tChar, mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness );
|
|
|
|
|
prevChar = *tChar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -738,20 +639,12 @@ void Text::setBackgroundColor( const Color& backgroundColor ) {
|
|
|
|
|
mBackgroundColor = backgroundColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Text::getDisableCacheWidth() const {
|
|
|
|
|
return mDisableCacheWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setDisableCacheWidth( bool newDisableCacheWidth ) {
|
|
|
|
|
mDisableCacheWidth = newDisableCacheWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Vector2f& Text::getShadowOffset() const {
|
|
|
|
|
return mShadowOffset;
|
|
|
|
|
return mFontStyleConfig.ShadowOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setShadowOffset( const Vector2f& shadowOffset ) {
|
|
|
|
|
mShadowOffset = shadowOffset;
|
|
|
|
|
mFontStyleConfig.ShadowOffset = shadowOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rectf Text::getLocalBounds() {
|
|
|
|
|
@@ -769,13 +662,14 @@ Float Text::getTextWidth() {
|
|
|
|
|
Float Text::getTextHeight() {
|
|
|
|
|
cacheWidth();
|
|
|
|
|
|
|
|
|
|
return NULL != mFont
|
|
|
|
|
? mFont->getLineSpacing( mRealFontSize ) * ( 0 == mNumLines ? 1 : mNumLines )
|
|
|
|
|
: 0;
|
|
|
|
|
return NULL != mFontStyleConfig.Font ? mFontStyleConfig.Font->getLineSpacing( mRealFontSize ) *
|
|
|
|
|
( mLinesWidth.empty() ? 1 : mLinesWidth.size() )
|
|
|
|
|
: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Float Text::getLineSpacing() {
|
|
|
|
|
return NULL != mFont ? mFont->getLineSpacing( mRealFontSize ) : 0;
|
|
|
|
|
return NULL != mFontStyleConfig.Font ? mFontStyleConfig.Font->getLineSpacing( mRealFontSize )
|
|
|
|
|
: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Float& rotation,
|
|
|
|
|
@@ -826,7 +720,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
|
|
|
|
p.drawRectangle( getLocalBounds() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Texture* texture = mFont->getTexture( mRealFontSize );
|
|
|
|
|
Texture* texture = mFontStyleConfig.Font->getTexture( mRealFontSize );
|
|
|
|
|
if ( !texture )
|
|
|
|
|
return;
|
|
|
|
|
texture->bind();
|
|
|
|
|
@@ -835,7 +729,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
|
|
|
|
Uint32 alloc = numvert * sizeof( VertexCoords );
|
|
|
|
|
Uint32 allocC = numvert * GLi->quadVertexs();
|
|
|
|
|
|
|
|
|
|
if ( 0 != mOutlineThickness ) {
|
|
|
|
|
if ( 0 != mFontStyleConfig.OutlineThickness ) {
|
|
|
|
|
GLi->colorPointer( 4, GL_UNSIGNED_BYTE, 0,
|
|
|
|
|
reinterpret_cast<const char*>( outlineColors.data() ), allocC );
|
|
|
|
|
GLi->texCoordPointer( 2, GL_FP, sizeof( VertexCoords ),
|
|
|
|
|
@@ -874,21 +768,21 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
|
|
|
|
void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Float& rotation,
|
|
|
|
|
BlendMode effect, const OriginPoint& rotationCenter,
|
|
|
|
|
const OriginPoint& scaleCenter ) {
|
|
|
|
|
if ( NULL == mFont )
|
|
|
|
|
if ( NULL == mFontStyleConfig.Font )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ensureColorUpdate();
|
|
|
|
|
ensureGeometryUpdate();
|
|
|
|
|
|
|
|
|
|
if ( mStyle & Shadow ) {
|
|
|
|
|
if ( mFontStyleConfig.Style & Shadow ) {
|
|
|
|
|
std::vector<Color> colors;
|
|
|
|
|
Color shadowColor( getShadowColor() );
|
|
|
|
|
if ( getFillColor().a != 255 )
|
|
|
|
|
shadowColor.a =
|
|
|
|
|
(Uint8)( (Float)shadowColor.a * ( (Float)getFillColor().a / (Float)255 ) );
|
|
|
|
|
colors.assign( mColors.size(), shadowColor );
|
|
|
|
|
draw( X + mShadowOffset.x, Y + mShadowOffset.y, scale, rotation, effect, rotationCenter,
|
|
|
|
|
scaleCenter, colors, {}, Color::Transparent );
|
|
|
|
|
draw( X + mFontStyleConfig.ShadowOffset.x, Y + mFontStyleConfig.ShadowOffset.y, scale,
|
|
|
|
|
rotation, effect, rotationCenter, scaleCenter, colors, {}, Color::Transparent );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
draw( X, Y, scale, rotation, effect, rotationCenter, scaleCenter, mColors, mOutlineColors,
|
|
|
|
|
@@ -896,7 +790,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::ensureGeometryUpdate() {
|
|
|
|
|
if ( !mDisableCacheWidth )
|
|
|
|
|
if ( mCachedWidthNeedUpdate && mAlign != TEXT_ALIGN_LEFT )
|
|
|
|
|
cacheWidth();
|
|
|
|
|
|
|
|
|
|
// Do nothing, if geometry has not changed
|
|
|
|
|
@@ -908,42 +802,45 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
|
|
|
|
|
// Clear the previous geometry
|
|
|
|
|
mVertices.clear();
|
|
|
|
|
mGlyphCache.clear();
|
|
|
|
|
mOutlineVertices.clear();
|
|
|
|
|
|
|
|
|
|
if ( mCachedWidthNeedUpdate )
|
|
|
|
|
mLinesWidth.clear();
|
|
|
|
|
|
|
|
|
|
mBounds = Rectf();
|
|
|
|
|
|
|
|
|
|
// No font or text: nothing to draw
|
|
|
|
|
if ( !mFont || mString.empty() )
|
|
|
|
|
if ( !mFontStyleConfig.Font || mString.empty() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mVertices.reserve( mString.size() * GLi->quadVertexs() );
|
|
|
|
|
mGlyphCache.reserve( mString.size() );
|
|
|
|
|
|
|
|
|
|
if ( mOutlineThickness != 0.f )
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0.f )
|
|
|
|
|
mOutlineVertices.reserve( mString.size() * GLi->quadVertexs() );
|
|
|
|
|
|
|
|
|
|
// Compute values related to the text style
|
|
|
|
|
bool bold = ( mStyle & Bold ) != 0;
|
|
|
|
|
bool reqItalic = ( mStyle & Italic ) != 0;
|
|
|
|
|
bool underlined = ( mStyle & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
|
|
|
|
|
Float italic = reqItalic && !mFont->hasItalic() ? 0.208f : 0.f; // 12 degrees
|
|
|
|
|
Float underlineOffset = mFont->getUnderlinePosition( mRealFontSize );
|
|
|
|
|
Float underlineThickness = mFont->getUnderlineThickness( mRealFontSize );
|
|
|
|
|
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
|
|
|
|
|
bool reqItalic = ( mFontStyleConfig.Style & Italic ) != 0;
|
|
|
|
|
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
|
|
|
|
|
Float italic = reqItalic && !mFontStyleConfig.Font->hasItalic() ? 0.208f : 0.f; // 12 degrees
|
|
|
|
|
Float underlineOffset = mFontStyleConfig.Font->getUnderlinePosition( mRealFontSize );
|
|
|
|
|
Float underlineThickness = mFontStyleConfig.Font->getUnderlineThickness( mRealFontSize );
|
|
|
|
|
|
|
|
|
|
// Compute the location of the strike through dynamically
|
|
|
|
|
// We use the center point of the lowercase 'x' glyph as the reference
|
|
|
|
|
// We reuse the underline thickness as the thickness of the strike through as well
|
|
|
|
|
Float strikeThroughOffset = 0;
|
|
|
|
|
if ( strikeThrough ) {
|
|
|
|
|
Rectf xBounds = mFont->getGlyph( L'x', mRealFontSize, bold, reqItalic ).bounds;
|
|
|
|
|
Rectf xBounds =
|
|
|
|
|
mFontStyleConfig.Font->getGlyph( L'x', mRealFontSize, bold, reqItalic ).bounds;
|
|
|
|
|
strikeThroughOffset = xBounds.Top + xBounds.Bottom / 2.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Precompute the variables needed by the algorithm
|
|
|
|
|
Float hspace =
|
|
|
|
|
static_cast<Float>( mFont->getGlyph( L' ', mRealFontSize, bold, reqItalic ).advance );
|
|
|
|
|
Float vspace = static_cast<Float>( mFont->getLineSpacing( mRealFontSize ) );
|
|
|
|
|
Float hspace = static_cast<Float>(
|
|
|
|
|
mFontStyleConfig.Font->getGlyph( L' ', mRealFontSize, bold, reqItalic ).advance );
|
|
|
|
|
Float vspace = static_cast<Float>( mFontStyleConfig.Font->getLineSpacing( mRealFontSize ) );
|
|
|
|
|
Float x = 0.f;
|
|
|
|
|
Float y = static_cast<Float>( mRealFontSize );
|
|
|
|
|
|
|
|
|
|
@@ -952,8 +849,10 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
Float minY = static_cast<Float>( mRealFontSize );
|
|
|
|
|
Float maxX = 0.f;
|
|
|
|
|
Float maxY = 0.f;
|
|
|
|
|
Float maxW = 0.f;
|
|
|
|
|
Uint32 prevChar = 0;
|
|
|
|
|
|
|
|
|
|
size_t size = mString.size();
|
|
|
|
|
Float centerDiffX = 0;
|
|
|
|
|
unsigned int line = 0;
|
|
|
|
|
|
|
|
|
|
@@ -970,21 +869,21 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( std::size_t i = 0; i < mString.size(); ++i ) {
|
|
|
|
|
for ( std::size_t i = 0; i < size; ++i ) {
|
|
|
|
|
Uint32 curChar = mString[i];
|
|
|
|
|
|
|
|
|
|
// Apply the kerning offset
|
|
|
|
|
x += mFont->getKerning( prevChar, curChar, mRealFontSize, bold, reqItalic,
|
|
|
|
|
mOutlineThickness );
|
|
|
|
|
x += mFontStyleConfig.Font->getKerning( prevChar, curChar, mRealFontSize, bold, reqItalic,
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
prevChar = curChar;
|
|
|
|
|
|
|
|
|
|
// If we're using the underlined style and there's a new line, draw a line
|
|
|
|
|
if ( underlined && ( curChar == L'\n' ) ) {
|
|
|
|
|
addLine( mVertices, x, y, underlineOffset, underlineThickness, 0, centerDiffX );
|
|
|
|
|
|
|
|
|
|
if ( mOutlineThickness != 0 )
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0 )
|
|
|
|
|
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness,
|
|
|
|
|
mOutlineThickness, centerDiffX );
|
|
|
|
|
mFontStyleConfig.OutlineThickness, centerDiffX );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we're using the strike through style and there's a new line, draw a line across all
|
|
|
|
|
@@ -992,9 +891,9 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
if ( strikeThrough && ( curChar == L'\n' ) ) {
|
|
|
|
|
addLine( mVertices, x, y, strikeThroughOffset, underlineThickness, 0, centerDiffX );
|
|
|
|
|
|
|
|
|
|
if ( mOutlineThickness != 0 )
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0 )
|
|
|
|
|
addLine( mOutlineVertices, x, y, strikeThroughOffset, underlineThickness,
|
|
|
|
|
mOutlineThickness, centerDiffX );
|
|
|
|
|
mFontStyleConfig.OutlineThickness, centerDiffX );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( curChar == L'\n' ) {
|
|
|
|
|
@@ -1015,27 +914,24 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle special characters
|
|
|
|
|
if ( ( curChar == ' ' ) || ( curChar == '\t' ) || ( curChar == '\n' ) ||
|
|
|
|
|
( curChar == '\r' ) ) {
|
|
|
|
|
if ( curChar == ' ' || curChar == '\t' || curChar == '\n' || curChar == '\r' ) {
|
|
|
|
|
// Update the current bounds (min coordinates)
|
|
|
|
|
minX = std::min( minX, x );
|
|
|
|
|
minY = std::min( minY, y );
|
|
|
|
|
|
|
|
|
|
switch ( curChar ) {
|
|
|
|
|
case ' ':
|
|
|
|
|
mGlyphCache.emplace_back(
|
|
|
|
|
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( hspace, vspace ) ) );
|
|
|
|
|
x += hspace;
|
|
|
|
|
break;
|
|
|
|
|
case '\t':
|
|
|
|
|
mGlyphCache.emplace_back( Rectf( Vector2f( x, y - mRealFontSize ),
|
|
|
|
|
Sizef( hspace * mTabWidth, vspace ) ) );
|
|
|
|
|
x += hspace * mTabWidth;
|
|
|
|
|
break;
|
|
|
|
|
case '\n':
|
|
|
|
|
mGlyphCache.emplace_back(
|
|
|
|
|
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( 0, vspace ) ) );
|
|
|
|
|
y += vspace;
|
|
|
|
|
|
|
|
|
|
if ( mCachedWidthNeedUpdate )
|
|
|
|
|
mLinesWidth.push_back( x );
|
|
|
|
|
|
|
|
|
|
x = 0;
|
|
|
|
|
break;
|
|
|
|
|
case '\r':
|
|
|
|
|
@@ -1046,14 +942,17 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
maxX = std::max( maxX, x );
|
|
|
|
|
maxY = std::max( maxY, y );
|
|
|
|
|
|
|
|
|
|
if ( mCachedWidthNeedUpdate )
|
|
|
|
|
maxW = std::max( maxW, x );
|
|
|
|
|
|
|
|
|
|
// Next glyph, no need to create a quad for whitespace
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply the outline
|
|
|
|
|
if ( mOutlineThickness != 0 ) {
|
|
|
|
|
const Glyph& glyph =
|
|
|
|
|
mFont->getGlyph( curChar, mRealFontSize, bold, italic, mOutlineThickness );
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0 ) {
|
|
|
|
|
const Glyph& glyph = mFontStyleConfig.Font->getGlyph(
|
|
|
|
|
curChar, mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness );
|
|
|
|
|
|
|
|
|
|
Float left = glyph.bounds.Left;
|
|
|
|
|
Float top = glyph.bounds.Top;
|
|
|
|
|
@@ -1061,24 +960,28 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
Float bottom = glyph.bounds.Top + glyph.bounds.Bottom;
|
|
|
|
|
|
|
|
|
|
// Add the outline glyph to the vertices
|
|
|
|
|
addGlyphQuad( mOutlineVertices, Vector2f( x, y ), glyph, italic, mOutlineThickness,
|
|
|
|
|
centerDiffX );
|
|
|
|
|
addGlyphQuad( mOutlineVertices, Vector2f( x, y ), glyph, italic,
|
|
|
|
|
mFontStyleConfig.OutlineThickness, centerDiffX );
|
|
|
|
|
|
|
|
|
|
// Update the current bounds with the outlined glyph bounds
|
|
|
|
|
minX = std::min( minX, x + left - italic * bottom - mOutlineThickness );
|
|
|
|
|
maxX = std::max( maxX, x + right - italic * top - mOutlineThickness );
|
|
|
|
|
minY = std::min( minY, y + top - mOutlineThickness );
|
|
|
|
|
maxY = std::max( maxY, y + bottom - mOutlineThickness );
|
|
|
|
|
minX = std::min( minX, x + left - italic * bottom - mFontStyleConfig.OutlineThickness );
|
|
|
|
|
maxX = std::max( maxX, x + right - italic * top - mFontStyleConfig.OutlineThickness );
|
|
|
|
|
minY = std::min( minY, y + top - mFontStyleConfig.OutlineThickness );
|
|
|
|
|
maxY = std::max( maxY, y + bottom - mFontStyleConfig.OutlineThickness );
|
|
|
|
|
if ( mCachedWidthNeedUpdate )
|
|
|
|
|
maxW = std::max( maxW, x + glyph.advance - italic * top -
|
|
|
|
|
mFontStyleConfig.OutlineThickness );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract the current glyph's description
|
|
|
|
|
const Glyph& glyph = mFont->getGlyph( curChar, mRealFontSize, bold, reqItalic );
|
|
|
|
|
const Glyph& glyph =
|
|
|
|
|
mFontStyleConfig.Font->getGlyph( curChar, mRealFontSize, bold, reqItalic );
|
|
|
|
|
|
|
|
|
|
// Add the glyph to the vertices
|
|
|
|
|
addGlyphQuad( mVertices, Vector2f( x, y ), glyph, italic, 0, centerDiffX );
|
|
|
|
|
|
|
|
|
|
// Update the current bounds with the non outlined glyph bounds
|
|
|
|
|
if ( mOutlineThickness == 0 ) {
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness == 0 ) {
|
|
|
|
|
Float left = glyph.bounds.Left;
|
|
|
|
|
Float top = glyph.bounds.Top;
|
|
|
|
|
Float right = glyph.bounds.Left + glyph.bounds.Right;
|
|
|
|
|
@@ -1088,40 +991,46 @@ void Text::ensureGeometryUpdate() {
|
|
|
|
|
maxX = std::max( maxX, x + right - italic * top );
|
|
|
|
|
minY = std::min( minY, y + top );
|
|
|
|
|
maxY = std::max( maxY, y + bottom );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mGlyphCache.emplace_back(
|
|
|
|
|
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( glyph.advance, vspace ) ) );
|
|
|
|
|
if ( mCachedWidthNeedUpdate )
|
|
|
|
|
maxW = std::max( maxW, x + glyph.advance - italic * top );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advance to the next character
|
|
|
|
|
x += glyph.advance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mGlyphCache.emplace_back( Rectf( Vector2f( x, y - mRealFontSize ), Sizef( 0, vspace ) ) );
|
|
|
|
|
|
|
|
|
|
// If we're using the underlined style, add the last line
|
|
|
|
|
if ( underlined && ( x > 0 ) ) {
|
|
|
|
|
addLine( mVertices, x, y, underlineOffset, underlineThickness, 0, centerDiffX );
|
|
|
|
|
|
|
|
|
|
if ( mOutlineThickness != 0 )
|
|
|
|
|
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness, mOutlineThickness,
|
|
|
|
|
centerDiffX );
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0 )
|
|
|
|
|
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness,
|
|
|
|
|
mFontStyleConfig.OutlineThickness, centerDiffX );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we're using the strike through style, add the last line across all characters
|
|
|
|
|
if ( strikeThrough && ( x > 0 ) ) {
|
|
|
|
|
addLine( mVertices, x, y, strikeThroughOffset, underlineThickness, 0, centerDiffX );
|
|
|
|
|
|
|
|
|
|
if ( mOutlineThickness != 0 )
|
|
|
|
|
if ( mFontStyleConfig.OutlineThickness != 0 )
|
|
|
|
|
addLine( mOutlineVertices, x, y, strikeThroughOffset, underlineThickness,
|
|
|
|
|
mOutlineThickness, centerDiffX );
|
|
|
|
|
mFontStyleConfig.OutlineThickness, centerDiffX );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( mCachedWidthNeedUpdate && !mString.empty() && mString[mString.size() - 1] != '\n' )
|
|
|
|
|
mLinesWidth.push_back( x );
|
|
|
|
|
|
|
|
|
|
// Update the bounding rectangle
|
|
|
|
|
mBounds.Left = minX;
|
|
|
|
|
mBounds.Top = minY;
|
|
|
|
|
mBounds.Right = maxX;
|
|
|
|
|
mBounds.Bottom = maxY;
|
|
|
|
|
|
|
|
|
|
if ( mCachedWidthNeedUpdate ) {
|
|
|
|
|
mCachedWidth = maxW;
|
|
|
|
|
mCachedWidthNeedUpdate = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::ensureColorUpdate() {
|
|
|
|
|
@@ -1129,15 +1038,15 @@ void Text::ensureColorUpdate() {
|
|
|
|
|
Uint32 tv = getTotalVertices();
|
|
|
|
|
|
|
|
|
|
if ( mColors.size() < tv )
|
|
|
|
|
mColors.resize( tv, mFillColor );
|
|
|
|
|
mColors.resize( tv, mFontStyleConfig.FontColor );
|
|
|
|
|
|
|
|
|
|
mColors.assign( tv, mFillColor );
|
|
|
|
|
mColors.assign( tv, mFontStyleConfig.FontColor );
|
|
|
|
|
|
|
|
|
|
if ( 0 != mOutlineThickness ) {
|
|
|
|
|
if ( 0 != mFontStyleConfig.OutlineThickness ) {
|
|
|
|
|
if ( mOutlineColors.size() < tv )
|
|
|
|
|
mOutlineColors.resize( tv, mOutlineColor );
|
|
|
|
|
mOutlineColors.resize( tv, mFontStyleConfig.OutlineColor );
|
|
|
|
|
|
|
|
|
|
mOutlineColors.assign( tv, mOutlineColor );
|
|
|
|
|
mOutlineColors.assign( tv, mFontStyleConfig.OutlineColor );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mColorsNeedUpdate = false;
|
|
|
|
|
@@ -1145,23 +1054,24 @@ void Text::ensureColorUpdate() {
|
|
|
|
|
if ( mContainsColorEmoji ) {
|
|
|
|
|
auto positions = Font::emojiCodePointsPositions( mString );
|
|
|
|
|
for ( const auto& position : positions )
|
|
|
|
|
setFillColor( Color( 255, 255, 255, mFillColor.a ), position, position );
|
|
|
|
|
setFillColor( Color( 255, 255, 255, mFontStyleConfig.FontColor.a ), position,
|
|
|
|
|
position );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Color& Text::getShadowColor() const {
|
|
|
|
|
return mShadowColor;
|
|
|
|
|
return mFontStyleConfig.ShadowColor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setShadowColor( const Color& color ) {
|
|
|
|
|
mShadowColor = color;
|
|
|
|
|
mFontStyleConfig.ShadowColor = color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int& Text::getNumLines() {
|
|
|
|
|
cacheWidth();
|
|
|
|
|
|
|
|
|
|
return mNumLines;
|
|
|
|
|
Uint32 Text::getNumLines() {
|
|
|
|
|
if ( !mCachedWidthNeedUpdate )
|
|
|
|
|
return mLinesWidth.size();
|
|
|
|
|
return mString.countChar( '\n' ) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::vector<Float>& Text::getLinesWidth() {
|
|
|
|
|
@@ -1185,14 +1095,12 @@ void Text::cacheWidth() {
|
|
|
|
|
if ( !mCachedWidthNeedUpdate )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( NULL != mFont && !mString.empty() ) {
|
|
|
|
|
getWidthInfo();
|
|
|
|
|
if ( NULL != mFontStyleConfig.Font && !mString.empty() ) {
|
|
|
|
|
updateWidthCache();
|
|
|
|
|
mCachedWidthNeedUpdate = false;
|
|
|
|
|
} else {
|
|
|
|
|
mCachedWidth = 0;
|
|
|
|
|
mNumLines = 0;
|
|
|
|
|
mLinesWidth.clear();
|
|
|
|
|
mLinesStartIndex.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1204,14 +1112,11 @@ void Text::setStyleConfig( const FontStyleConfig& styleConfig ) {
|
|
|
|
|
setOutlineThickness( styleConfig.OutlineThickness );
|
|
|
|
|
setOutlineColor( styleConfig.OutlineColor );
|
|
|
|
|
setShadowColor( styleConfig.ShadowColor );
|
|
|
|
|
setShadowOffset( styleConfig.ShadowOffset );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Text::hasSameFontStyleConfig( const FontStyleConfig& styleConfig ) {
|
|
|
|
|
return styleConfig.Font == mFont && styleConfig.CharacterSize == mFontSize &&
|
|
|
|
|
styleConfig.Style == mStyle && styleConfig.FontColor == mFillColor &&
|
|
|
|
|
styleConfig.OutlineColor == mOutlineColor && styleConfig.ShadowColor == mShadowColor &&
|
|
|
|
|
styleConfig.ShadowOffset == mShadowOffset &&
|
|
|
|
|
styleConfig.OutlineThickness == mOutlineThickness;
|
|
|
|
|
return mFontStyleConfig == styleConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
|
|
|
|
|
@@ -1220,8 +1125,8 @@ void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
|
|
|
|
|
|
|
|
|
|
ensureColorUpdate();
|
|
|
|
|
|
|
|
|
|
bool underlined = ( mStyle & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
|
|
|
|
|
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
|
|
|
|
|
std::size_t s = mString.size();
|
|
|
|
|
|
|
|
|
|
if ( to >= s ) {
|
|
|
|
|
@@ -1463,8 +1368,8 @@ void Text::addGlyphQuad( std::vector<VertexCoords>& vertices, Vector2f position,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint32 Text::getTotalVertices() {
|
|
|
|
|
bool underlined = ( mStyle & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
|
|
|
|
|
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
|
|
|
|
|
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
|
|
|
|
|
size_t sl = mString.size();
|
|
|
|
|
size_t sv = sl * GLi->quadVertexs();
|
|
|
|
|
|
|
|
|
|
|