mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-14 05:06:54 +03:00
Fix background color in Text (should render over text and not the bounding rectangle.
Having fixed this added background color to UIRichText and UITextSpan.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -29,13 +29,15 @@ class FontStyleConfig {
|
||||
|
||||
const Vector2f& getFontShadowOffset() const { return ShadowOffset; }
|
||||
|
||||
const Color& getBackgroundColor() const { return BackgroundColor; }
|
||||
|
||||
FontStyleConfig() {}
|
||||
|
||||
bool operator==( const FontStyleConfig& other ) {
|
||||
return Font == other.Font && CharacterSize == other.CharacterSize && Style == other.Style &&
|
||||
FontColor == other.FontColor && ShadowColor == other.ShadowColor &&
|
||||
ShadowOffset == other.ShadowOffset && OutlineThickness == other.OutlineThickness &&
|
||||
OutlineColor == other.OutlineColor;
|
||||
OutlineColor == other.OutlineColor && BackgroundColor == other.BackgroundColor;
|
||||
}
|
||||
|
||||
bool operator!=( const FontStyleConfig& other ) { return !( *this == other ); }
|
||||
@@ -49,6 +51,7 @@ class FontStyleConfig {
|
||||
ShadowOffset = fontStyleConfig.ShadowOffset;
|
||||
OutlineThickness = fontStyleConfig.OutlineThickness;
|
||||
OutlineColor = fontStyleConfig.OutlineColor;
|
||||
BackgroundColor = fontStyleConfig.BackgroundColor;
|
||||
}
|
||||
|
||||
Graphics::Font* Font{ nullptr };
|
||||
@@ -59,6 +62,7 @@ class FontStyleConfig {
|
||||
Vector2f ShadowOffset{ PixelDensity::dpToPx( 1 ), PixelDensity::dpToPx( 1 ) };
|
||||
Float OutlineThickness{ 0 };
|
||||
Color OutlineColor{ 0, 0, 0, 255 };
|
||||
Color BackgroundColor{ Color::Transparent };
|
||||
};
|
||||
|
||||
}} // namespace EE::Graphics
|
||||
|
||||
@@ -41,7 +41,8 @@ class EE_API RichText : public Drawable {
|
||||
* @param style The text style (optional, uses default if Regular).
|
||||
*/
|
||||
void addSpan( const String& text, Font* font = nullptr, Uint32 characterSize = 0,
|
||||
Color color = Color::White, Uint32 style = Text::Regular );
|
||||
Color color = Color::White, Uint32 style = Text::Regular,
|
||||
Color backgroundColor = Color::Transparent );
|
||||
|
||||
/** @brief Clears all text spans. */
|
||||
void clear();
|
||||
|
||||
@@ -400,7 +400,6 @@ class EE_API Text {
|
||||
|
||||
String mString; ///< String to display
|
||||
FontStyleConfig mFontStyleConfig;
|
||||
Color mBackgroundColor{ Color::Transparent };
|
||||
|
||||
mutable Rectf mBounds; ///< Bounding rectangle of the text (in local coordinates)
|
||||
mutable bool mGeometryNeedUpdate : 1 { false }; ///< Does the geometry need to be recomputed?
|
||||
|
||||
@@ -63,6 +63,10 @@ class EE_API UIRichText : public UILayout {
|
||||
|
||||
UIRichText* setFontColor( const Color& color );
|
||||
|
||||
const Color& getFontBackgroundColor() const;
|
||||
|
||||
UIRichText* setFontBackgroundColor( const Color& color );
|
||||
|
||||
const Color& getFontShadowColor() const;
|
||||
|
||||
UIRichText* setFontShadowColor( const Color& color );
|
||||
|
||||
@@ -77,6 +77,10 @@ class EE_API UITextSpan : public UIWidget {
|
||||
|
||||
UITextSpan* setFontColor( const Color& color );
|
||||
|
||||
const Color& getFontBackgroundColor() const;
|
||||
|
||||
UITextSpan* setFontBackgroundColor( const Color& color );
|
||||
|
||||
const Color& getFontShadowColor() const;
|
||||
|
||||
UITextSpan* setFontShadowColor( const Color& color );
|
||||
@@ -97,6 +101,7 @@ class EE_API UITextSpan : public UIWidget {
|
||||
StyleStateOutlineColor = 1 << 5,
|
||||
StyleStateFontShadowColor = 1 << 6,
|
||||
StyleStateFontShadowOffset = 1 << 7,
|
||||
StyleStateFontBackgroundColor = 1 << 8,
|
||||
StyleStateAll = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
@@ -108,6 +113,7 @@ class EE_API UITextSpan : public UIWidget {
|
||||
bool hasOutlineColor() const;
|
||||
bool hasFontShadowColor() const;
|
||||
bool hasFontShadowOffset() const;
|
||||
bool hasFontBackgroundColor() const;
|
||||
|
||||
protected:
|
||||
Uint32 mStyleState{ StyleStateNone };
|
||||
|
||||
@@ -168,18 +168,20 @@ LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, Uin
|
||||
? font->getGlyph( curChar, characterSize, bold, italic, outlineThickness ).advance
|
||||
: hspace;
|
||||
|
||||
Float kerning = 0;
|
||||
if ( curChar == '\t' ) {
|
||||
w = Text::tabAdvance( hspace, tabWidth, tabStops ? xoffset : std::optional<Float>{} );
|
||||
prevChar = 0;
|
||||
} else if ( !isMonospace && curChar != '\r' ) {
|
||||
if ( !( textDrawHints & TextHints::NoKerning ) ) {
|
||||
w += font->getKerning( prevChar, curChar, characterSize, bold, italic,
|
||||
outlineThickness );
|
||||
kerning = font->getKerning( prevChar, curChar, characterSize, bold, italic,
|
||||
outlineThickness );
|
||||
}
|
||||
prevChar = curChar;
|
||||
}
|
||||
|
||||
xoffset += w;
|
||||
Float xpos = xoffset + kerning;
|
||||
xoffset = xpos + w;
|
||||
|
||||
if ( hasWrap && xoffset > maxWidth ) {
|
||||
if ( mode == LineWrapMode::Word && lastSpace != std::string::npos ) {
|
||||
@@ -188,7 +190,15 @@ LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, Uin
|
||||
}
|
||||
|
||||
info.wraps.push_back( lastSpace + 1 );
|
||||
xoffset = info.paddingStart + ( xoffset - lastWidth );
|
||||
|
||||
Float startKerning = 0;
|
||||
if ( !( textDrawHints & TextHints::NoKerning ) && !isMonospace &&
|
||||
lastSpace + 1 < string.size() ) {
|
||||
startKerning = font->getKerning( string[lastSpace], string[lastSpace + 1],
|
||||
characterSize, bold, italic, outlineThickness );
|
||||
}
|
||||
|
||||
xoffset = info.paddingStart + ( xoffset - lastWidth - startKerning );
|
||||
} else {
|
||||
// If we are about to split a word, check if we can move it to the next line
|
||||
if ( mode == LineWrapMode::Word && info.wraps.size() == 1 &&
|
||||
@@ -213,6 +223,7 @@ LineWrap::computeLineBreaksInternal( const String::View& string, Font* font, Uin
|
||||
|
||||
info.wraps.push_back( idx );
|
||||
xoffset = info.paddingStart;
|
||||
prevChar = 0;
|
||||
}
|
||||
}
|
||||
lastSpace = std::string::npos;
|
||||
|
||||
@@ -98,7 +98,7 @@ void RichText::addCustomSize( const Sizef& size ) {
|
||||
}
|
||||
|
||||
void RichText::addSpan( const String& text, Font* font, Uint32 characterSize, Color color,
|
||||
Uint32 style ) {
|
||||
Uint32 style, Color backgroundColor ) {
|
||||
FontStyleConfig config;
|
||||
config.Font = font ? font : mDefaultStyle.Font;
|
||||
config.CharacterSize = characterSize != 0 ? characterSize : mDefaultStyle.CharacterSize;
|
||||
@@ -108,6 +108,7 @@ void RichText::addSpan( const String& text, Font* font, Uint32 characterSize, Co
|
||||
config.ShadowOffset = mDefaultStyle.ShadowOffset;
|
||||
config.OutlineThickness = mDefaultStyle.OutlineThickness;
|
||||
config.OutlineColor = mDefaultStyle.OutlineColor;
|
||||
config.BackgroundColor = backgroundColor;
|
||||
|
||||
addSpan( text, config );
|
||||
}
|
||||
|
||||
@@ -1575,11 +1575,11 @@ const Uint32& Text::getTabWidth() const {
|
||||
}
|
||||
|
||||
Color Text::getBackgroundColor() const {
|
||||
return mBackgroundColor;
|
||||
return mFontStyleConfig.BackgroundColor;
|
||||
}
|
||||
|
||||
void Text::setBackgroundColor( const Color& backgroundColor ) {
|
||||
mBackgroundColor = backgroundColor;
|
||||
mFontStyleConfig.BackgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
const Vector2f& Text::getShadowOffset() const {
|
||||
@@ -1629,11 +1629,11 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
||||
BlendMode effect, const OriginPoint& rotationCenter,
|
||||
const OriginPoint& scaleCenter, const std::vector<Color>& colors,
|
||||
const std::vector<Color>& outlineColors, const Color& backgroundColor ) {
|
||||
unsigned int numvert = mVertices.size();
|
||||
|
||||
if ( 0 == numvert )
|
||||
if ( NULL == mFontStyleConfig.Font || mString.empty() )
|
||||
return;
|
||||
|
||||
unsigned int numvert = mVertices.size();
|
||||
|
||||
GlobalBatchRenderer::instance()->draw();
|
||||
|
||||
if ( rotation != 0.0f || scale != 1.0f ) {
|
||||
@@ -1670,7 +1670,32 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
||||
Primitives p;
|
||||
p.setForceDraw( true );
|
||||
p.setColor( backgroundColor );
|
||||
p.drawRectangle( getLocalBounds() );
|
||||
ensureVisualLinesUpdate();
|
||||
Float vspace = getLineSpacing();
|
||||
for ( size_t i = 0; i < mVisualLines.size(); ++i ) {
|
||||
Float centerDiffX = 0;
|
||||
if ( i < mLinesWidth.size() ) {
|
||||
switch ( Font::getHorizontalAlign( mAlign ) ) {
|
||||
case TEXT_ALIGN_CENTER:
|
||||
centerDiffX = std::trunc( ( mCachedWidth - mLinesWidth[i] ) * 0.5f );
|
||||
break;
|
||||
case TEXT_ALIGN_RIGHT:
|
||||
centerDiffX = mCachedWidth - mLinesWidth[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.drawRectangle( Rectf( centerDiffX, i * vspace, centerDiffX + mLinesWidth[i],
|
||||
( i + 1 ) * vspace ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == numvert ) {
|
||||
if ( rotation != 0.0f || scale != 1.0f ) {
|
||||
GLi->popMatrix();
|
||||
} else {
|
||||
GLi->translatef( -X, -Y, 0 );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Texture* texture = mFontStyleConfig.Font->getTexture( mFontStyleConfig.CharacterSize );
|
||||
@@ -1744,7 +1769,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
||||
}
|
||||
|
||||
draw( X, Y, scale, rotation, effect, rotationCenter, scaleCenter, mColors, mOutlineColors,
|
||||
mBackgroundColor );
|
||||
mFontStyleConfig.BackgroundColor );
|
||||
}
|
||||
|
||||
void Text::ensureGeometryUpdate() {
|
||||
@@ -2330,6 +2355,7 @@ void Text::setStyleConfig( const FontStyleConfig& styleConfig ) {
|
||||
setOutlineColor( styleConfig.OutlineColor );
|
||||
setShadowColor( styleConfig.ShadowColor );
|
||||
setShadowOffset( styleConfig.ShadowOffset );
|
||||
setBackgroundColor( styleConfig.BackgroundColor );
|
||||
}
|
||||
|
||||
bool Text::hasSameFontStyleConfig( const FontStyleConfig& styleConfig ) {
|
||||
|
||||
@@ -620,11 +620,18 @@ void TextLayout::wrapLayout( const String::View& string, TextLayout& result,
|
||||
breakStringIdx = string.size();
|
||||
|
||||
ShapedGlyph& breakGlyph = sp.shapedGlyphs[breakIndex];
|
||||
Float breakPos = breakGlyph.position.x;
|
||||
Float kerning = 0;
|
||||
if ( breakIndex > 0 ) {
|
||||
ShapedGlyph& prevBreakGlyph = sp.shapedGlyphs[breakIndex - 1];
|
||||
kerning = ( prevBreakGlyph.position.x + prevBreakGlyph.advance.x ) -
|
||||
breakGlyph.position.x;
|
||||
}
|
||||
|
||||
sp.wrapInfo.wraps.push_back( breakStringIdx );
|
||||
sp.wrapInfo.wrapsWidth.push_back( std::ceil( breakGlyph.position.x ) );
|
||||
sp.wrapInfo.wrapsWidth.push_back( std::ceil( breakPos + kerning ) );
|
||||
|
||||
Vector2f adjustment( -breakGlyph.position.x + sp.wrapInfo.paddingStart, vspace );
|
||||
Vector2f adjustment( sp.wrapInfo.paddingStart - breakGlyph.position.x, vspace );
|
||||
for ( std::size_t k = breakIndex; k <= idx; ++k )
|
||||
sp.shapedGlyphs[k].position += adjustment;
|
||||
|
||||
|
||||
@@ -98,6 +98,9 @@ bool UIRichText::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
case PropertyId::Color:
|
||||
setFontColor( attribute.asColor() );
|
||||
break;
|
||||
case PropertyId::BackgroundColor:
|
||||
setFontBackgroundColor( attribute.asColor() );
|
||||
break;
|
||||
case PropertyId::TextShadowColor:
|
||||
setFontShadowColor( attribute.asColor() );
|
||||
break;
|
||||
@@ -141,6 +144,8 @@ std::string UIRichText::getPropertyString( const PropertyDefinition* propertyDef
|
||||
return Graphics::Text::styleFlagToString( getFontStyle() );
|
||||
case PropertyId::Color:
|
||||
return getFontColor().toHexString();
|
||||
case PropertyId::BackgroundColor:
|
||||
return getFontBackgroundColor().toHexString();
|
||||
case PropertyId::TextShadowColor:
|
||||
return getFontShadowColor().toHexString();
|
||||
case PropertyId::TextShadowOffset:
|
||||
@@ -161,10 +166,10 @@ std::string UIRichText::getPropertyString( const PropertyDefinition* propertyDef
|
||||
|
||||
std::vector<PropertyId> UIRichText::getPropertiesImplemented() const {
|
||||
auto props = UILayout::getPropertiesImplemented();
|
||||
auto local = {
|
||||
PropertyId::FontFamily, PropertyId::FontSize, PropertyId::FontStyle,
|
||||
PropertyId::Color, PropertyId::TextShadowColor, PropertyId::TextShadowOffset,
|
||||
PropertyId::TextStrokeWidth, PropertyId::TextStrokeColor, PropertyId::TextAlign };
|
||||
auto local = { PropertyId::FontFamily, PropertyId::FontSize, PropertyId::FontStyle,
|
||||
PropertyId::Color, PropertyId::BackgroundColor, PropertyId::TextShadowColor,
|
||||
PropertyId::TextShadowOffset, PropertyId::TextStrokeWidth, PropertyId::TextStrokeColor,
|
||||
PropertyId::TextAlign };
|
||||
props.insert( props.end(), local.begin(), local.end() );
|
||||
return props;
|
||||
}
|
||||
@@ -229,6 +234,19 @@ UIRichText* UIRichText::setFontColor( const Color& color ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const Color& UIRichText::getFontBackgroundColor() const {
|
||||
return mRichText.getFontStyleConfig().BackgroundColor;
|
||||
}
|
||||
|
||||
UIRichText* UIRichText::setFontBackgroundColor( const Color& color ) {
|
||||
if ( mRichText.getFontStyleConfig().BackgroundColor != color ) {
|
||||
mRichText.getFontStyleConfig().BackgroundColor = color;
|
||||
mRichText.invalidate();
|
||||
updateDefaultSpansStyle();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
const Color& UIRichText::getFontShadowColor() const {
|
||||
return mRichText.getFontStyleConfig().ShadowColor;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ bool UITextSpan::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
case PropertyId::Color:
|
||||
setFontColor( attribute.asColor() );
|
||||
break;
|
||||
case PropertyId::BackgroundColor:
|
||||
setFontBackgroundColor( attribute.asColor() );
|
||||
break;
|
||||
case PropertyId::TextShadowColor:
|
||||
setFontShadowColor( attribute.asColor() );
|
||||
break;
|
||||
@@ -112,6 +115,8 @@ std::string UITextSpan::getPropertyString( const PropertyDefinition* propertyDef
|
||||
return Graphics::Text::styleFlagToString( getFontStyle() );
|
||||
case PropertyId::Color:
|
||||
return getFontColor().toHexString();
|
||||
case PropertyId::BackgroundColor:
|
||||
return getFontBackgroundColor().toHexString();
|
||||
case PropertyId::TextShadowColor:
|
||||
return getFontShadowColor().toHexString();
|
||||
case PropertyId::TextShadowOffset:
|
||||
@@ -133,6 +138,7 @@ std::vector<PropertyId> UITextSpan::getPropertiesImplemented() const {
|
||||
PropertyId::FontSize,
|
||||
PropertyId::FontStyle,
|
||||
PropertyId::Color,
|
||||
PropertyId::BackgroundColor,
|
||||
PropertyId::TextShadowColor,
|
||||
PropertyId::TextShadowOffset,
|
||||
PropertyId::TextStrokeWidth,
|
||||
@@ -248,6 +254,19 @@ UITextSpan* UITextSpan::setFontColor( const Color& color ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const Color& UITextSpan::getFontBackgroundColor() const {
|
||||
return mFontStyleConfig.getBackgroundColor();
|
||||
}
|
||||
|
||||
UITextSpan* UITextSpan::setFontBackgroundColor( const Color& color ) {
|
||||
if ( mFontStyleConfig.BackgroundColor != color ) {
|
||||
mFontStyleConfig.BackgroundColor = color;
|
||||
mStyleState |= StyleStateFontBackgroundColor;
|
||||
onFontStyleChanged();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
const Color& UITextSpan::getFontShadowColor() const {
|
||||
return mFontStyleConfig.getFontShadowColor();
|
||||
}
|
||||
@@ -404,6 +423,12 @@ void UITextSpan::setInheritedStyle( const UIFontStyleConfig& fontStyleConfig ) {
|
||||
fontStyleChanged = true;
|
||||
}
|
||||
|
||||
if ( !hasFontBackgroundColor() &&
|
||||
mFontStyleConfig.BackgroundColor != fontStyleConfig.BackgroundColor ) {
|
||||
mFontStyleConfig.BackgroundColor = fontStyleConfig.BackgroundColor;
|
||||
fontStyleChanged = true;
|
||||
}
|
||||
|
||||
if ( fontChanged )
|
||||
onFontChanged();
|
||||
|
||||
@@ -454,4 +479,8 @@ bool UITextSpan::hasFontShadowOffset() const {
|
||||
return 0 != ( mStyleState & StyleStateFontShadowOffset );
|
||||
}
|
||||
|
||||
bool UITextSpan::hasFontBackgroundColor() const {
|
||||
return 0 != ( mStyleState & StyleStateFontBackgroundColor );
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -1434,3 +1434,69 @@ UTEST( FontRendering, TextContiguousOffset ) {
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
UTEST( FontRendering, TextBackgroundColor ) {
|
||||
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
||||
|
||||
const auto runTest = [&]() {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 512, 400, "eepp - Text Background Color", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false, true ) );
|
||||
|
||||
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
||||
|
||||
win->setClearColor( RGB( 255, 255, 255 ) );
|
||||
win->clear();
|
||||
|
||||
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
||||
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
||||
|
||||
Vector2f pos{ 20, 20 };
|
||||
Text text;
|
||||
text.setFont( font );
|
||||
text.setFontSize( 20 );
|
||||
text.setFillColor( Color::Black );
|
||||
text.setBackgroundColor( Color::Yellow );
|
||||
text.setString( "Text with background color\nand multiple lines." );
|
||||
text.draw( pos.x, pos.y );
|
||||
|
||||
pos.y += text.getTextHeight() + 20;
|
||||
text.setAlign( TEXT_ALIGN_CENTER );
|
||||
text.setString( "Centered text with\nbackground color." );
|
||||
text.draw( pos.x, pos.y );
|
||||
|
||||
pos.y += text.getTextHeight() + 20;
|
||||
text.setAlign( TEXT_ALIGN_LEFT );
|
||||
text.setLineWrapMode( LineWrapMode::Word );
|
||||
text.setMaxWrapWidth( 200 );
|
||||
text.setString(
|
||||
"Wrapped text with background color that should only cover the text area." );
|
||||
text.draw( pos.x, pos.y );
|
||||
|
||||
pos.y += text.getTextHeight() + 20;
|
||||
text.setLineWrapMode( LineWrapMode::NoWrap );
|
||||
text.setBackgroundColor( Color::cyan );
|
||||
text.setString( " " ); // Only spaces
|
||||
text.draw( pos.x, pos.y );
|
||||
|
||||
compareImages( utest_state, utest_result, win, "eepp-text-background-color" );
|
||||
|
||||
Engine::destroySingleton();
|
||||
};
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper disabled" );
|
||||
{
|
||||
BoolScopedOp op( Text::TextShaperEnabled, false );
|
||||
runTest();
|
||||
}
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
||||
{
|
||||
BoolScopedOp op( Text::TextShaperEnabled, true );
|
||||
runTest();
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
|
||||
BoolScopedOp op2( Text::TextShaperOptimizations, false );
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user