From 52117490d94d8242addbe1608efe64364fdb308a Mon Sep 17 00:00:00 2001 From: Richard Underhill Date: Thu, 9 Apr 2015 14:05:12 +0100 Subject: [PATCH] Added UNDERLINE_HEIGHT property to TextLabel to override adaptor metrics and rounded up font metrics to simulate EFL behavior Change-Id: I52dbf0d609716e6d2e18de22cbc8489a67abaef3 Signed-off-by: Richard Underhill --- .../controls/text-controls/text-label-impl.cpp | 23 +++ .../text/rendering/atlas/text-atlas-renderer.cpp | 161 ++++++++++++--------- dali-toolkit/internal/text/text-controller.cpp | 11 ++ dali-toolkit/internal/text/text-controller.h | 14 ++ dali-toolkit/internal/text/text-view-interface.h | 9 +- dali-toolkit/internal/text/text-view.cpp | 10 ++ dali-toolkit/internal/text/text-view.h | 5 + dali-toolkit/internal/text/visual-model-impl.cpp | 17 ++- dali-toolkit/internal/text/visual-model-impl.h | 21 ++- .../public-api/controls/text-controls/text-label.h | 27 ++-- 10 files changed, 212 insertions(+), 86 deletions(-) diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 73f40e9..43d0cff 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -88,6 +88,7 @@ DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-offset", VECTOR2, SHADOW_O DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-color", VECTOR4, SHADOW_COLOR ) DALI_PROPERTY_REGISTRATION( TextLabel, "underline-enabled", BOOLEAN, UNDERLINE_ENABLED ) DALI_PROPERTY_REGISTRATION( TextLabel, "underline-color", VECTOR4, UNDERLINE_COLOR ) +DALI_PROPERTY_REGISTRATION( TextLabel, "underline-height", FLOAT, UNDERLINE_HEIGHT ) DALI_TYPE_REGISTRATION_END() } // namespace @@ -289,6 +290,20 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr } break; } + + case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + { + if( impl.mController ) + { + float height = value.Get< float >(); + if ( impl.mController->GetUnderlineHeight() != height ) + { + impl.mController->SetUnderlineHeight( height ); + impl.RequestTextRelayout(); + } + } + break; + } } } } @@ -387,6 +402,14 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } break; } + case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + { + if ( impl.mController ) + { + value = impl.mController->GetUnderlineHeight(); + } + break; + } } } diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index fda82f4..016284a 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -19,6 +19,7 @@ #include // EXTERNAL INCLUDES +#include #include #include @@ -38,6 +39,10 @@ using namespace Dali::Toolkit::Text; namespace { + const float ZERO( 0.0f ); + const float HALF( 0.5f ); + const float ONE( 1.0f ); + const float TWO( 2.0f ); const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f ); const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f ); const Vector2 PADDING( 4.0f, 4.0f ); // Allow for variation in font glyphs @@ -102,19 +107,21 @@ struct AtlasRenderer::Impl : public ConnectionTracker const Vector4& textColor, const Vector2& shadowOffset, const Vector4& shadowColor, - float underlineEnabled, - const Vector4& underlineColor ) + bool underlineEnabled, + const Vector4& underlineColor, + float underlineHeight ) { AtlasManager::AtlasSlot slot; std::vector< MeshRecord > meshContainer; Vector< Extent > extents; - float currentUnderlinePosition = 0.0f; - float currentUnderlineThickness = 0.0f; + float currentUnderlinePosition = ZERO; + float currentUnderlineThickness = underlineHeight; + FontId lastFontId = 0; Style style = STYLE_NORMAL; - if ( shadowOffset.x != 0.0f || shadowOffset.y != 0.0f ) + if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 ) { style = STYLE_DROP_SHADOW; } @@ -140,13 +147,33 @@ struct AtlasRenderer::Impl : public ConnectionTracker // We need to fetch fresh font underline metrics FontMetrics fontMetrics; mFontClient.GetFontMetrics( glyph.fontId, fontMetrics ); - currentUnderlinePosition = fontMetrics.underlinePosition; - currentUnderlineThickness = fontMetrics.underlineThickness; + currentUnderlinePosition = FontMetricsRoundUp( fabsf( fontMetrics.underlinePosition ) ); + float descender = FontMetricsRoundUp( fabsf( fontMetrics.descender ) ); - // Ensure that an underline is at least 1 pixel high - if ( currentUnderlineThickness < 1.0f ) + if ( underlineHeight == ZERO ) { - currentUnderlineThickness = 1.0f; + currentUnderlineThickness = fontMetrics.underlineThickness; + + // Ensure underline will be at least a pixel high + if ( currentUnderlineThickness < ONE ) + { + currentUnderlineThickness = ONE; + } + else + { + currentUnderlineThickness = FontMetricsRoundUp( currentUnderlineThickness ); + } + } + + // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font + if ( currentUnderlinePosition > descender ) + { + currentUnderlinePosition = descender; + } + if ( ZERO == currentUnderlinePosition ) + { + // Move offset down by one ( EFL behavior ) + currentUnderlinePosition = ONE; } } @@ -173,7 +200,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, mBlockSizes[ j ].mNeededBlockSize ); } } - lastFontId = glyph.fontId; } // Glyph doesn't currently exist in atlas so upload @@ -199,6 +225,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker currentUnderlineThickness, slot ); } + lastFontId = glyph.fontId; } if ( underlineEnabled ) @@ -289,14 +316,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker uint32_t index = 0; for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index ) { - if ( slot.mAtlasId == mIt->mAtlasId ) + if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor ) { // Stitch the mesh to the existing mesh and adjust any extents mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData ); AdjustExtents( extents, meshContainer, index, - color, left, right, baseLine, @@ -318,7 +344,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker AdjustExtents( extents, meshContainer, meshContainer.size() - 1u, - color, left, right, baseLine, @@ -331,7 +356,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker void AdjustExtents( Vector< Extent >& extents, std::vector< MeshRecord>& meshRecords, uint32_t index, - const Vector4& color, float left, float right, float baseLine, @@ -343,21 +367,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker { if ( Equals( baseLine, eIt->mBaseLine ) ) { - // If we've found an extent with the same color then we don't need to create a new extent - if ( color == meshRecords[ index ].mColor ) + foundExtent = true; + if ( left < eIt->mLeft ) { - foundExtent = true; - if ( left < eIt->mLeft ) - { - eIt->mLeft = left; - } - if ( right > eIt->mRight ) - { - eIt->mRight = right; - } + eIt->mLeft = left; } - // Font metrics use negative values for lower underline positions - if ( underlinePosition < eIt->mUnderlinePosition ) + if ( right > eIt->mRight ) + { + eIt->mRight = right; + } + + if ( underlinePosition > eIt->mUnderlinePosition ) { eIt->mUnderlinePosition = underlinePosition; } @@ -431,15 +451,25 @@ struct AtlasRenderer::Impl : public ConnectionTracker } } + float FontMetricsRoundUp( float value ) + { + double integral_part; + if ( modf( value, &integral_part ) ) + { + return ( static_cast< float >( integral_part ) + 1.0f ); + } + else + { + return static_cast< float >( integral_part ); + } + } + void GenerateUnderlines( std::vector< MeshRecord>& meshRecords, Vector< Extent >& extents, const Vector4& underlineColor, const Vector4& textColor ) { MeshData newMeshData; - const float zero = 0.0f; - const float half = 0.5f; - for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt ) { MeshData::VertexContainer newVerts; @@ -448,28 +478,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId ); // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas ) - float u = half / uv.x; - float v = half / uv.y; + float u = HALF / uv.x; + float v = HALF / uv.y; float thickness = eIt->mUnderlineThickness; - float baseLine = eIt->mBaseLine - eIt->mUnderlinePosition - ( thickness * 0.5f ); + float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF ); float tlx = eIt->mLeft; float brx = eIt->mRight; - newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, zero ), - Vector2( zero, zero ), - Vector3( zero, zero, zero ) ) ); + newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, ZERO ), + Vector2::ZERO, + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, zero ), - Vector2( u, zero ), - Vector3( zero, zero, zero ) ) ); + newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, ZERO ), + Vector2( u, ZERO ), + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, zero ), - Vector2( zero, v ), - Vector3( zero, zero, zero ) ) ); + newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, ZERO ), + Vector2( ZERO, v ), + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, zero ), + newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, ZERO ), Vector2( u, v ), - Vector3( zero, zero, zero ) ) ); + Vector3::ZERO ) ); newMeshData.SetVertices( newVerts ); newMeshData.SetFaceIndices( mFace ); @@ -500,12 +530,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker { // Scan vertex buffer to determine width and height of effect buffer needed MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices(); - const float one = 1.0f; - const float zero = 0.0f; float tlx = verts[ 0 ].x; float tly = verts[ 0 ].y; - float brx = zero; - float bry = zero; + float brx = ZERO; + float bry = ZERO; for ( uint32_t i = 0; i < verts.size(); ++i ) { @@ -529,8 +557,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker float width = brx - tlx; float height = bry - tly; - float divWidth = 2.0f / width; - float divHeight = 2.0f / height; + float divWidth = TWO / width; + float divHeight = TWO / height; // Create a buffer to render to meshRecord.mBuffer = FrameBufferImage::New( width, height ); @@ -539,21 +567,21 @@ struct AtlasRenderer::Impl : public ConnectionTracker MeshData::VertexContainer vertices; MeshData::FaceIndices face; - vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, zero ), - Vector2( zero, zero ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, ZERO ), + Vector2::ZERO, + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, zero ), - Vector2( one, zero ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, ZERO ), + Vector2( ONE, ZERO ), + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, zero ), - Vector2( zero, one ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, ZERO ), + Vector2( ZERO, ONE ), + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, zero ), - Vector2( one, one ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, ZERO ), + Vector2::ONE, + Vector3::ZERO ) ); MeshData meshData; Material newMaterial = Material::New("effect buffer"); @@ -578,8 +606,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker for ( uint32_t i = 0; i < verts.size(); ++i ) { MeshData::Vertex vertex = verts[ i ]; - vertex.x = ( ( vertex.x - tlx ) * divWidth ) - one; - vertex.y = ( ( vertex.y - tly ) * divHeight ) - one; + vertex.x = ( ( vertex.x - tlx ) * divWidth ) - ONE; + vertex.y = ( ( vertex.y - tly ) * divHeight ) - ONE; newVerts.push_back( vertex ); } @@ -676,7 +704,8 @@ RenderableActor AtlasRenderer::Render( Text::ViewInterface& view ) view.GetShadowOffset(), view.GetShadowColor(), view.IsUnderlineEnabled(), - view.GetUnderlineColor() ); + view.GetUnderlineColor(), + view.GetUnderlineHeight() ); } return mImpl->mActor; } diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 7d05f52..d86d4f5 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -987,6 +987,7 @@ struct Controller::Impl mVisualModel->SetShadowOffset( Vector2::ZERO ); mVisualModel->SetShadowColor( Vector4::ZERO ); mVisualModel->SetUnderlineEnabled( false ); + mVisualModel->SetUnderlineHeight( 0.0f ); } ~Impl() @@ -1210,6 +1211,11 @@ bool Controller::IsUnderlineEnabled() const return mImpl->mVisualModel->IsUnderlineEnabled(); } +float Controller::GetUnderlineHeight() const +{ + return mImpl->mVisualModel->GetUnderlineHeight(); +} + void Controller::SetTextColor( const Vector4& textColor ) { mImpl->mVisualModel->SetTextColor( textColor ); @@ -1235,6 +1241,11 @@ void Controller::SetUnderlineEnabled( bool enabled ) mImpl->mVisualModel->SetUnderlineEnabled( enabled ); } +void Controller::SetUnderlineHeight( float height ) +{ + mImpl->mVisualModel->SetUnderlineHeight( height ); +} + void Controller::EnableTextInput( DecoratorPtr decorator ) { if( !mImpl->mTextInput ) diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 0234e7c..076897a 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -243,6 +243,20 @@ public: bool IsUnderlineEnabled() const; /** + * @brief Set the override used for underline height, 0 indicates height will be supplied by adaptor + * + * @param[in] height The height in pixels of the underline + */ + void SetUnderlineHeight( float height ); + + /** + * @brief Retrieves the override height of an underline, 0 indicates height is supplied by adaptor + * + * @return The height of the underline, or 0 if height is not overrided. + */ + float GetUnderlineHeight() const; + + /** * @brief Called to enable text input. * * @note Only selectable or editable controls should calls this. diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h index 116ad50..68d5e97 100644 --- a/dali-toolkit/internal/text/text-view-interface.h +++ b/dali-toolkit/internal/text/text-view-interface.h @@ -117,12 +117,19 @@ public: virtual const Vector4& GetUnderlineColor() const = 0; /** - * @brief Returns whether is underline is enabled or not. + * @brief Returns whether underline is enabled or not. * * @return The underline state. */ virtual bool IsUnderlineEnabled() const = 0; + /** + * @brief Retrieves the underline height override + * + * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height + */ + virtual float GetUnderlineHeight() const = 0; + }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index b0825f6..61073fe 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -101,6 +101,16 @@ bool View::IsUnderlineEnabled() const return false; } +float View::GetUnderlineHeight() const +{ + if ( mImpl->mVisualModel ) + { + VisualModel& model = *mImpl->mVisualModel; + return model.GetUnderlineHeight(); + } + return 0.0f; +} + Length View::GetNumberOfGlyphs() const { if( mImpl->mVisualModel ) diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h index b9bd7fc..e611c3c 100644 --- a/dali-toolkit/internal/text/text-view.h +++ b/dali-toolkit/internal/text/text-view.h @@ -101,6 +101,11 @@ public: */ virtual bool IsUnderlineEnabled() const; + /** + * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight() + */ + virtual float GetUnderlineHeight() const; + private: // Undefined diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index c070179..a5fead4 100644 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -441,6 +441,11 @@ void VisualModel::SetUnderlineEnabled( bool enabled ) mUnderlineEnabled = enabled; } +void VisualModel::SetUnderlineHeight( float height ) +{ + mUnderlineHeight = height; +} + const Vector4& VisualModel::GetTextColor() const { return mTextColor; @@ -466,6 +471,11 @@ bool VisualModel::IsUnderlineEnabled() const return mUnderlineEnabled; } +float VisualModel::GetUnderlineHeight() const +{ + return mUnderlineHeight; +} + void VisualModel::ClearCaches() { mCachedLineIndex = 0u; @@ -487,11 +497,12 @@ VisualModel::VisualModel() mShadowColor(), mUnderlineColor(), mShadowOffset(), + mUnderlineHeight( 0.0f ), + mUnderlineEnabled( false ), + mUnderlineColorSet( false ), mNaturalSize(), mActualSize(), - mCachedLineIndex( 0u ), - mUnderlineEnabled( false ), - mUnderlineColorSet( false ) + mCachedLineIndex( 0u ) { } diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index aa8a75f..292adc7 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -477,6 +477,20 @@ public: */ void ClearCaches(); + /** + * @brief Set the override used for underline height, 0 indicates height will be supplied by adaptor + * + * @param[in] height The height in pixels of the underline + */ + void SetUnderlineHeight( float height ); + + /** + * @brief Retrieves the underline height override + * + * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height + */ + float GetUnderlineHeight() const; + protected: /** @@ -511,6 +525,10 @@ public: Vector4 mShadowColor; ///< Color of drop shadow Vector4 mUnderlineColor; ///< Color of underline Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow + float mUnderlineHeight; ///< Fixed height for underline to override adaptor supplied settings. + bool mUnderlineEnabled:1; ///< Underline enabled flag + bool mUnderlineColorSet:1; ///< Has the underline color been explicitly set? + private: @@ -520,9 +538,6 @@ private: // Caches to increase performance in some consecutive operations. LineIndex mCachedLineIndex; ///< Used to increase performance in consecutive calls to GetLineOfGlyph() or GetLineOfCharacter() with consecutive glyphs or characters. -public: - bool mUnderlineEnabled:1; ///< Underline enabled flag - bool mUnderlineColorSet:1; ///< Has the underline color been explicitly set? }; } // namespace Text diff --git a/dali-toolkit/public-api/controls/text-controls/text-label.h b/dali-toolkit/public-api/controls/text-controls/text-label.h index 7ecb200..b11bd13 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-label.h +++ b/dali-toolkit/public-api/controls/text-controls/text-label.h @@ -57,19 +57,20 @@ public: { enum { - RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "rendering-backend", The type or rendering e.g. bitmap-based, type INT - TEXT, ///< name "text", The text to display in UTF-8 format, type STRING - FONT_FAMILY, ///< name "font-family", The requested font family, type STRING - FONT_STYLE, ///< name "font-style", The requested font style e.g. Regular/Italic, type STRING - POINT_SIZE, ///< name "point-size", The size of font in points, type FLOAT - MULTI_LINE, ///< name "multi-line", The single-line or multi-line layout option, type BOOLEAN - HORIZONTAL_ALIGNMENT, ///< name "horizontal-alignment", The line horizontal alignment, type STRING, values "BEGIN", "CENTER", "END" - VERTICAL_ALIGNMENT, ///< name "vertical-alignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM" - TEXT_COLOR, ///< name "text-color", The text color, type VECTOR4 - SHADOW_OFFSET, ///< name "shadow-offset", The drop shadow offset 0 indicates no shadow, type VECTOR2 - SHADOW_COLOR, ///< name "shadow-color", The color of a drop shadow, type VECTOR4 - UNDERLINE_ENABLED, ///< name "underline-enabled", The underline enabled flag type BOOLEAN - UNDERLINE_COLOR, ///< name "underline-color", The color of the underline type VECTOR4 + RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "rendering-backend", The type or rendering e.g. bitmap-based, type INT + TEXT, ///< name "text", The text to display in UTF-8 format, type STRING + FONT_FAMILY, ///< name "font-family", The requested font family, type STRING + FONT_STYLE, ///< name "font-style", The requested font style e.g. Regular/Italic, type STRING + POINT_SIZE, ///< name "point-size", The size of font in points, type FLOAT + MULTI_LINE, ///< name "multi-line", The single-line or multi-line layout option, type BOOLEAN + HORIZONTAL_ALIGNMENT, ///< name "horizontal-alignment", The line horizontal alignment, type STRING, values "BEGIN", "CENTER", "END" + VERTICAL_ALIGNMENT, ///< name "vertical-alignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM" + TEXT_COLOR, ///< name "text-color", The text color, type VECTOR4 + SHADOW_OFFSET, ///< name "shadow-offset", The drop shadow offset 0 indicates no shadow, type VECTOR2 + SHADOW_COLOR, ///< name "shadow-color", The color of a drop shadow, type VECTOR4 + UNDERLINE_ENABLED, ///< name "underline-enabled", The underline enabled flag, type BOOLEAN + UNDERLINE_COLOR, ///< name "underline-color", The color of the underline, type VECTOR4 + UNDERLINE_HEIGHT ///< name "underline-height", Overrides the underline height from font metrics, type FLOAT }; }; -- 2.7.4