X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Ftext-controls%2Ftext-label-impl.cpp;h=d1dff137d89f5d2d974ef2459a782fb6612126c7;hp=784a5c89a937cc88fef72cf3fda8d61edc18c9b4;hb=92cbca2f5bd2e15fa589448d4c884b71f4fef03c;hpb=50106cc2737496e2b27b2a6d089f205321678a41 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 784a5c8..1beb1c2 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,67 +19,77 @@ #include // EXTERNAL INCLUDES -#include +#include +#include +#include #include #include +#include +#include // INTERNAL INCLUDES -#include #include -#include +#include +#include #include #include +#include #include #include #include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include using namespace Dali::Toolkit::Text; namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { - const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND; -} +const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND; -namespace -{ +/** + * @brief How the text visual should be aligned vertically inside the control. + * + * 0.0f aligns the text to the top, 0.5f aligns the text to the center, 1.0f aligns the text to the bottom. + * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations). + */ +const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] = + { + 0.0f, // VerticalAlignment::TOP + 0.5f, // VerticalAlignment::CENTER + 1.0f // VerticalAlignment::BOTTOM +}; + +const std::string TEXT_FIT_ENABLE_KEY("enable"); +const std::string TEXT_FIT_MIN_SIZE_KEY("minSize"); +const std::string TEXT_FIT_MAX_SIZE_KEY("maxSize"); +const std::string TEXT_FIT_STEP_SIZE_KEY("stepSize"); +const std::string TEXT_FIT_FONT_SIZE_TYPE_KEY("fontSizeType"); -#if defined ( DEBUG_ENABLED ) - Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] = -{ - { "IMMEDIATE", Toolkit::DevelTextLabel::AutoScrollStopMode::IMMEDIATE }, - { "FINISH_LOOP", Toolkit::DevelTextLabel::AutoScrollStopMode::FINISH_LOOP }, -}; -const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof( AUTO_SCROLL_STOP_MODE_TABLE ) / sizeof( AUTO_SCROLL_STOP_MODE_TABLE[0] ); - -const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] = -{ - { "BEGIN", Toolkit::Text::Layout::HORIZONTAL_ALIGN_BEGIN }, - { "CENTER", Toolkit::Text::Layout::HORIZONTAL_ALIGN_CENTER }, - { "END", Toolkit::Text::Layout::HORIZONTAL_ALIGN_END }, -}; -const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] ); - -const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] = -{ - { "TOP", Toolkit::Text::Layout::VERTICAL_ALIGN_TOP }, - { "CENTER", Toolkit::Text::Layout::VERTICAL_ALIGN_CENTER }, - { "BOTTOM", Toolkit::Text::Layout::VERTICAL_ALIGN_BOTTOM }, + { + {"IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE}, + {"FINISH_LOOP", Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP}, }; -const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( VERTICAL_ALIGNMENT_STRING_TABLE ) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] ); +const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof(AUTO_SCROLL_STOP_MODE_TABLE) / sizeof(AUTO_SCROLL_STOP_MODE_TABLE[0]); // Type registration BaseHandle Create() @@ -87,50 +97,130 @@ BaseHandle Create() return Toolkit::TextLabel::New(); } +// clang-format off // Setup properties, signals and actions using the type-registry. -DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create ); - -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "renderingBackend", INTEGER, RENDERING_BACKEND ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text", STRING, TEXT ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontFamily", STRING, FONT_FAMILY ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontStyle", MAP, FONT_STYLE ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pointSize", FLOAT, POINT_SIZE ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "multiLine", BOOLEAN, MULTI_LINE ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "horizontalAlignment", STRING, HORIZONTAL_ALIGNMENT ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalAlignment", STRING, VERTICAL_ALIGNMENT ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textColor", VECTOR4, TEXT_COLOR ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowOffset", VECTOR2, SHADOW_OFFSET ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadowColor", VECTOR4, SHADOW_COLOR ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineEnabled", BOOLEAN, UNDERLINE_ENABLED ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineColor", VECTOR4, UNDERLINE_COLOR ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underlineHeight", FLOAT, UNDERLINE_HEIGHT ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "enableMarkup", BOOLEAN, ENABLE_MARKUP ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "enableAutoScroll", BOOLEAN, ENABLE_AUTO_SCROLL ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollSpeed", INTEGER, AUTO_SCROLL_SPEED ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopCount", INTEGER, AUTO_SCROLL_LOOP_COUNT ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollGap", FLOAT, AUTO_SCROLL_GAP ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "lineSpacing", FLOAT, LINE_SPACING ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "underline", MAP, UNDERLINE ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "shadow", MAP, SHADOW ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "emboss", MAP, EMBOSS ) -DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "outline", MAP, OUTLINE ) -DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pixelSize", FLOAT, PIXEL_SIZE ) -DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "ellipsis", BOOLEAN, ELLIPSIS ) -DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopDelay", FLOAT, AUTO_SCROLL_LOOP_DELAY ) -DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollStopMode", STRING, AUTO_SCROLL_STOP_MODE ) -DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "lineCount", INTEGER, LINE_COUNT ) +DALI_TYPE_REGISTRATION_BEGIN(Toolkit::TextLabel, Toolkit::Control, Create); + +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "text", STRING, TEXT ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "fontFamily", STRING, FONT_FAMILY ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "fontStyle", MAP, FONT_STYLE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "pointSize", FLOAT, POINT_SIZE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "multiLine", BOOLEAN, MULTI_LINE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "horizontalAlignment", STRING, HORIZONTAL_ALIGNMENT ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "verticalAlignment", STRING, VERTICAL_ALIGNMENT ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "enableMarkup", BOOLEAN, ENABLE_MARKUP ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "enableAutoScroll", BOOLEAN, ENABLE_AUTO_SCROLL ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "autoScrollSpeed", INTEGER, AUTO_SCROLL_SPEED ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "autoScrollLoopCount", INTEGER, AUTO_SCROLL_LOOP_COUNT ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "autoScrollGap", FLOAT, AUTO_SCROLL_GAP ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "lineSpacing", FLOAT, LINE_SPACING ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "underline", MAP, UNDERLINE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "shadow", MAP, SHADOW ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "emboss", MAP, EMBOSS ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "outline", MAP, OUTLINE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "pixelSize", FLOAT, PIXEL_SIZE ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "ellipsis", BOOLEAN, ELLIPSIS ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "autoScrollLoopDelay", FLOAT, AUTO_SCROLL_LOOP_DELAY ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "autoScrollStopMode", STRING, AUTO_SCROLL_STOP_MODE ) +DALI_PROPERTY_REGISTRATION_READ_ONLY(Toolkit, TextLabel, "lineCount", INTEGER, LINE_COUNT ) +DALI_PROPERTY_REGISTRATION(Toolkit, TextLabel, "lineWrapMode", INTEGER, LINE_WRAP_MODE ) +DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY(Toolkit, TextLabel, "textDirection", INTEGER, TEXT_DIRECTION ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "verticalLineAlignment", INTEGER, VERTICAL_LINE_ALIGNMENT ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "textBackground", MAP, BACKGROUND ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "ignoreSpacesAfterText", BOOLEAN, IGNORE_SPACES_AFTER_TEXT ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "textFit", MAP, TEXT_FIT ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "minLineSize", FLOAT, MIN_LINE_SIZE ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "renderingBackend", INTEGER, RENDERING_BACKEND ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "fontSizeScale", FLOAT, FONT_SIZE_SCALE ) + +DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR ) +DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0) +DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1) +DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorBlue", TEXT_COLOR_BLUE, TEXT_COLOR, 2) +DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3) + +DALI_SIGNAL_REGISTRATION(Toolkit, TextLabel, "anchorClicked", SIGNAL_ANCHOR_CLICKED) DALI_TYPE_REGISTRATION_END() +// clang-format on + +/// Parses the property map for the TEXT_FIT property +void ParseTextFitProperty(Text::ControllerPtr& controller, const Property::Map* propertiesMap) +{ + if(propertiesMap && !propertiesMap->Empty()) + { + bool enabled = false; + float minSize = 0.f; + float maxSize = 0.f; + float stepSize = 0.f; + bool isMinSizeSet = false, isMaxSizeSet = false, isStepSizeSet = false; + Controller::FontSizeType type = Controller::FontSizeType::POINT_SIZE; + + const unsigned int numberOfItems = propertiesMap->Count(); + + // Parses and applies + for(unsigned int index = 0u; index < numberOfItems; ++index) + { + const KeyValuePair& valueGet = propertiesMap->GetKeyValue(index); + + if((Controller::TextFitInfo::Property::TEXT_FIT_ENABLE == valueGet.first.indexKey) || (TEXT_FIT_ENABLE_KEY == valueGet.first.stringKey)) + { + /// Enable key. + enabled = valueGet.second.Get(); + } + else if((Controller::TextFitInfo::Property::TEXT_FIT_MIN_SIZE == valueGet.first.indexKey) || (TEXT_FIT_MIN_SIZE_KEY == valueGet.first.stringKey)) + { + /// min size. + minSize = valueGet.second.Get(); + isMinSizeSet = true; + } + else if((Controller::TextFitInfo::Property::TEXT_FIT_MAX_SIZE == valueGet.first.indexKey) || (TEXT_FIT_MAX_SIZE_KEY == valueGet.first.stringKey)) + { + /// max size. + maxSize = valueGet.second.Get(); + isMaxSizeSet = true; + } + else if((Controller::TextFitInfo::Property::TEXT_FIT_STEP_SIZE == valueGet.first.indexKey) || (TEXT_FIT_STEP_SIZE_KEY == valueGet.first.stringKey)) + { + /// step size. + stepSize = valueGet.second.Get(); + isStepSizeSet = true; + } + else if((Controller::TextFitInfo::Property::TEXT_FIT_FONT_SIZE_TYPE == valueGet.first.indexKey) || (TEXT_FIT_FONT_SIZE_TYPE_KEY == valueGet.first.stringKey)) + { + if("pixelSize" == valueGet.second.Get()) + { + type = Controller::FontSizeType::PIXEL_SIZE; + } + } + } + + controller->SetTextFitEnabled(enabled); + if(isMinSizeSet) + { + controller->SetTextFitMinSize(minSize, type); + } + if(isMaxSizeSet) + { + controller->SetTextFitMaxSize(maxSize, type); + } + if(isStepSizeSet) + { + controller->SetTextFitStepSize(stepSize, type); + } + } +} } // namespace Toolkit::TextLabel TextLabel::New() { // Create the implementation, temporarily owned by this handle on stack - IntrusivePtr< TextLabel > impl = new TextLabel(); + IntrusivePtr impl = new TextLabel(); // Pass ownership to CustomActor handle - Toolkit::TextLabel handle( *impl ); + Toolkit::TextLabel handle(*impl); // Second-phase init of the implementation // This can only be done after the CustomActor connection has been made... @@ -139,611 +229,492 @@ Toolkit::TextLabel TextLabel::New() return handle; } -void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) { - Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) ); + Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(Dali::BaseHandle(object)); - if( label ) + if(label) { - TextLabel& impl( GetImpl( label ) ); - switch( index ) + TextLabel& impl(GetImpl(label)); + DALI_ASSERT_ALWAYS(impl.mController && "No text contoller"); + + switch(index) { - case Toolkit::TextLabel::Property::RENDERING_BACKEND: + case Toolkit::DevelTextLabel::Property::RENDERING_BACKEND: { - int backend = value.Get< int >(); + int backend = value.Get(); #ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING - if( Text::RENDERING_VECTOR_BASED == backend ) + if(DevelText::RENDERING_VECTOR_BASED == backend) { backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering } #endif - if( impl.mRenderingBackend != backend ) + if(impl.mRenderingBackend != backend) { impl.mRenderingBackend = backend; - impl.mRenderer.Reset(); + impl.mTextUpdateNeeded = true; - if( impl.mController ) - { - // When using the vector-based rendering, the size of the GLyphs are different - TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH; - impl.mController->SetGlyphType( glyphType ); - } + // When using the vector-based rendering, the size of the GLyphs are different + TextAbstraction::GlyphType glyphType = (DevelText::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH; + impl.mController->SetGlyphType(glyphType); } break; } case Toolkit::TextLabel::Property::TEXT: { - if( impl.mController ) - { - impl.mController->SetText( value.Get< std::string >() ); - } + impl.mController->SetText(value.Get()); break; } case Toolkit::TextLabel::Property::FONT_FAMILY: { - if( impl.mController ) - { - const std::string& fontFamily = value.Get< std::string >(); + const std::string& fontFamily = value.Get(); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() ); - impl.mController->SetDefaultFontFamily( fontFamily ); - } + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str()); + impl.mController->SetDefaultFontFamily(fontFamily); break; } case Toolkit::TextLabel::Property::FONT_STYLE: { - SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT ); + SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT); break; } case Toolkit::TextLabel::Property::POINT_SIZE: { - if( impl.mController ) - { - const float pointSize = value.Get< float >(); + const float pointSize = value.Get(); - if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) ) - { - impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE ); - } + if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize)) + { + impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE); } break; } case Toolkit::TextLabel::Property::MULTI_LINE: { - if( impl.mController ) - { - impl.mController->SetMultiLineEnabled( value.Get< bool >() ); - } + impl.mController->SetMultiLineEnabled(value.Get()); break; } case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT: { - if( impl.mController ) + Text::HorizontalAlignment::Type alignment(static_cast(-1)); // Set to invalid value to ensure a valid mode does get set + if(Text::GetHorizontalAlignmentEnumeration(value, alignment)) { - Layout::HorizontalAlignment alignment( Layout::HORIZONTAL_ALIGN_BEGIN ); - if( Scripting::GetEnumeration< Toolkit::Text::Layout::HorizontalAlignment >( value.Get< std::string >().c_str(), - HORIZONTAL_ALIGNMENT_STRING_TABLE, - HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT, - alignment ) ) - { - impl.mController->SetHorizontalAlignment( alignment ); - } + impl.mController->SetHorizontalAlignment(alignment); } break; } case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT: { - if( impl.mController ) + Toolkit::Text::VerticalAlignment::Type alignment(static_cast(-1)); // Set to invalid value to ensure a valid mode does get set + if(Text::GetVerticalAlignmentEnumeration(value, alignment)) { - Layout::VerticalAlignment alignment( Layout::VERTICAL_ALIGN_BOTTOM ); - if( Scripting::GetEnumeration< Toolkit::Text::Layout::VerticalAlignment >( value.Get< std::string >().c_str(), - VERTICAL_ALIGNMENT_STRING_TABLE, - VERTICAL_ALIGNMENT_STRING_TABLE_COUNT, - alignment ) ) - { - impl.mController->SetVerticalAlignment( alignment ); - } + impl.mController->SetVerticalAlignment(alignment); } break; } - - case Toolkit::TextLabel::Property::TEXT_COLOR: + case Toolkit::TextLabel::Property::ENABLE_MARKUP: { - if( impl.mController ) - { - const Vector4& textColor = value.Get< Vector4 >(); - if( impl.mController->GetDefaultColor() != textColor ) - { - impl.mController->SetDefaultColor( textColor ); - impl.mRenderer.Reset(); - } - } + const bool enableMarkup = value.Get(); + impl.mController->SetMarkupProcessorEnabled(enableMarkup); break; } - - case Toolkit::TextLabel::Property::SHADOW_OFFSET: + case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: { - if( impl.mController ) + const bool enableAutoScroll = value.Get(); + // If request to auto scroll is the same as current state then do nothing. + if(enableAutoScroll != impl.mController->IsAutoScrollEnabled()) { - const Vector2& shadowOffset = value.Get< Vector2 >(); - if ( impl.mController->GetShadowOffset() != shadowOffset ) + // If request is disable (false) and auto scrolling is enabled then need to stop it + if(enableAutoScroll == false) { - impl.mController->SetShadowOffset( shadowOffset ); - impl.mRenderer.Reset(); + if(impl.mTextScroller) + { + impl.mTextScroller->StopScrolling(); + } + } + // If request is enable (true) then start autoscroll as not already running + else + { + impl.mController->SetAutoScrollEnabled(enableAutoScroll); } } break; } - case Toolkit::TextLabel::Property::SHADOW_COLOR: + case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE: { - if( impl.mController ) + Text::TextScrollerPtr textScroller = impl.GetTextScroller(); + Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = textScroller->GetStopMode(); + if(Scripting::GetEnumerationProperty(value, + AUTO_SCROLL_STOP_MODE_TABLE, + AUTO_SCROLL_STOP_MODE_TABLE_COUNT, + stopMode)) { - const Vector4& shadowColor = value.Get< Vector4 >(); - if ( impl.mController->GetShadowColor() != shadowColor ) - { - impl.mController->SetShadowColor( shadowColor ); - impl.mRenderer.Reset(); - } + textScroller->SetStopMode(stopMode); } break; } - case Toolkit::TextLabel::Property::UNDERLINE_COLOR: + case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED: { - if( impl.mController ) - { - const Vector4& color = value.Get< Vector4 >(); - if ( impl.mController->GetUnderlineColor() != color ) - { - impl.mController->SetUnderlineColor( color ); - impl.mRenderer.Reset(); - } - } + impl.GetTextScroller()->SetSpeed(value.Get()); break; } - case Toolkit::TextLabel::Property::UNDERLINE_ENABLED: + case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT: { - if( impl.mController ) - { - const bool enabled = value.Get< bool >(); - if ( impl.mController->IsUnderlineEnabled() != enabled ) - { - impl.mController->SetUnderlineEnabled( enabled ); - impl.mRenderer.Reset(); - } - } + impl.GetTextScroller()->SetLoopCount(value.Get()); break; } - - case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY: { - if( impl.mController ) - { - float height = value.Get< float >(); - if( fabsf( impl.mController->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 ) - { - impl.mController->SetUnderlineHeight( height ); - impl.mRenderer.Reset(); - } - } + impl.GetTextScroller()->SetLoopDelay(value.Get()); break; } - case Toolkit::TextLabel::Property::ENABLE_MARKUP: + case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP: { - if( impl.mController ) - { - const bool enableMarkup = value.Get(); - impl.mController->SetMarkupProcessorEnabled( enableMarkup ); - } + impl.GetTextScroller()->SetGap(value.Get()); break; } - case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: + case Toolkit::TextLabel::Property::LINE_SPACING: { - if( impl.mController ) - { - const bool enableAutoScroll = value.Get(); - // If request to auto scroll is the same as current state then do nothing. - if ( enableAutoScroll != impl.mController->IsAutoScrollEnabled() ) - { - // If request is disable (false) and auto scrolling is enabled then need to stop it - if ( enableAutoScroll == false ) - { - if( impl.mTextScroller ) - { - impl.mTextScroller->StopScrolling(); - } - } - // If request is enable (true) then start autoscroll as not already running - else - { - impl.mController->SetTextElideEnabled( false ); - impl.mController->SetAutoScrollEnabled( enableAutoScroll ); - } - } - } + const float lineSpacing = value.Get(); + impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSpacing(lineSpacing) || impl.mTextUpdateNeeded; break; } - case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE: + case Toolkit::TextLabel::Property::UNDERLINE: { - if( !impl.mTextScroller ) - { - impl.mTextScroller = Text::TextScroller::New( impl ); - } - DevelTextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode(); - if( Scripting::GetEnumerationProperty< Toolkit::DevelTextLabel::AutoScrollStopMode::Type >( value, - AUTO_SCROLL_STOP_MODE_TABLE, - AUTO_SCROLL_STOP_MODE_TABLE_COUNT, - stopMode ) ) - { - impl.mTextScroller->SetStopMode( stopMode ); - } + impl.mTextUpdateNeeded = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded; break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED: + case Toolkit::TextLabel::Property::SHADOW: { - if( !impl.mTextScroller ) - { - impl.mTextScroller = Text::TextScroller::New( impl ); - } - impl.mTextScroller->SetSpeed( value.Get() ); + impl.mTextUpdateNeeded = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded; break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT: + case Toolkit::TextLabel::Property::EMBOSS: { - if( !impl.mTextScroller ) - { - impl.mTextScroller = Text::TextScroller::New( impl ); - } - impl.mTextScroller->SetLoopCount( value.Get() ); + impl.mTextUpdateNeeded = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded; break; } - case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_LOOP_DELAY: + case Toolkit::TextLabel::Property::OUTLINE: { - if( !impl.mTextScroller ) - { - impl.mTextScroller = Text::TextScroller::New( impl ); - } - impl.mTextScroller->SetLoopDelay( value.Get() ); + impl.mTextUpdateNeeded = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded; break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP: + case Toolkit::TextLabel::Property::PIXEL_SIZE: { - if( !impl.mTextScroller ) + const float pixelSize = value.Get(); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize); + + if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize)) { - impl.mTextScroller = Text::TextScroller::New( impl ); + impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE); } - impl.mTextScroller->SetGap( value.Get() ); break; } - case Toolkit::TextLabel::Property::LINE_SPACING: + case Toolkit::TextLabel::Property::ELLIPSIS: { - if( impl.mController ) - { - const float lineSpacing = value.Get(); - impl.mController->SetDefaultLineSpacing( lineSpacing ); - impl.mRenderer.Reset(); - } + const bool ellipsis = value.Get(); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis); + + impl.mController->SetTextElideEnabled(ellipsis); break; } - case Toolkit::TextLabel::Property::UNDERLINE: + case Toolkit::TextLabel::Property::LINE_WRAP_MODE: { - const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); - if( update ) + Text::LineWrap::Mode lineWrapMode(static_cast(-1)); // Set to invalid value to ensure a valid mode does get set + if(GetLineWrapModeEnumeration(value, lineWrapMode)) { - impl.mRenderer.Reset(); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode); + impl.mController->SetLineWrapMode(lineWrapMode); } break; } - case Toolkit::TextLabel::Property::SHADOW: + case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT: { - const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); - if( update ) + if(impl.mController->GetTextModel()) { - impl.mRenderer.Reset(); + DevelText::VerticalLineAlignment::Type alignment = static_cast(value.Get()); + + impl.mController->SetVerticalLineAlignment(alignment); + + // Property doesn't affect the layout, only Visual must be updated + TextVisual::EnableRendererUpdate(impl.mVisual); + + // No need to trigger full re-layout. Instead call UpdateRenderer() directly + TextVisual::UpdateRenderer(impl.mVisual); } break; } - case Toolkit::TextLabel::Property::EMBOSS: + case Toolkit::DevelTextLabel::Property::BACKGROUND: { - const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); - if( update ) - { - impl.mRenderer.Reset(); - } + impl.mTextUpdateNeeded = SetBackgroundProperties(impl.mController, value, Text::EffectStyle::DEFAULT) || impl.mTextUpdateNeeded; break; } - case Toolkit::TextLabel::Property::OUTLINE: + case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT: { - const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); - if( update ) - { - impl.mRenderer.Reset(); - } + impl.mController->SetIgnoreSpacesAfterText(value.Get()); break; } - case Toolkit::DevelTextLabel::Property::PIXEL_SIZE: + case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION: { - if( impl.mController ) - { - const float pixelSize = value.Get< float >(); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize ); - - if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) ) - { - impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE ); - } - } + impl.mController->SetMatchSystemLanguageDirection(value.Get()); break; } - case Toolkit::DevelTextLabel::Property::ELLIPSIS: + case Toolkit::DevelTextLabel::Property::TEXT_FIT: { - if( impl.mController ) - { - const bool ellipsis = value.Get(); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis ); + ParseTextFitProperty(impl.mController, value.GetMap()); + break; + } + case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: + { + const float lineSize = value.Get(); + impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize(lineSize) || impl.mTextUpdateNeeded; + break; + } + case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE: + { + const float scale = value.Get(); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale); - impl.mController->SetTextElideEnabled( ellipsis ); + if(!Equals(impl.mController->GetFontSizeScale(), scale)) + { + impl.mController->SetFontSizeScale(scale); } break; } } + + // Request relayout when text update is needed. It's necessary to call it + // as changing the property not via UI interaction brings no effect if only + // the mTextUpdateNeeded is changed. + if(impl.mTextUpdateNeeded) + { + // need to request relayout as size of text may have changed + impl.RequestTextRelayout(); + } } } -Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index ) +Text::ControllerPtr TextLabel::getController() +{ + return mController; +} + +Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index) { Property::Value value; - Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) ); + Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(Dali::BaseHandle(object)); - if( label ) + if(label) { - TextLabel& impl( GetImpl( label ) ); - switch( index ) + TextLabel& impl(GetImpl(label)); + DALI_ASSERT_DEBUG(impl.mController && "No text contoller"); + + switch(index) { - case Toolkit::TextLabel::Property::RENDERING_BACKEND: + case Toolkit::DevelTextLabel::Property::RENDERING_BACKEND: { value = impl.mRenderingBackend; break; } case Toolkit::TextLabel::Property::TEXT: { - if( impl.mController ) - { - std::string text; - impl.mController->GetText( text ); - value = text; - } + std::string text; + impl.mController->GetText(text); + value = text; break; } case Toolkit::TextLabel::Property::FONT_FAMILY: { - if( impl.mController ) - { - value = impl.mController->GetDefaultFontFamily(); - } + value = impl.mController->GetDefaultFontFamily(); break; } case Toolkit::TextLabel::Property::FONT_STYLE: { - GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT ); + GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT); break; } case Toolkit::TextLabel::Property::POINT_SIZE: { - if( impl.mController ) - { - value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ); - } + value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE); break; } case Toolkit::TextLabel::Property::MULTI_LINE: { - if( impl.mController ) - { - value = impl.mController->IsMultiLineEnabled(); - } + value = impl.mController->IsMultiLineEnabled(); break; } case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT: { - if( impl.mController ) + const char* name = Text::GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment()); + + if(name) { - const char* name = Scripting::GetEnumerationName< Toolkit::Text::Layout::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(), - HORIZONTAL_ALIGNMENT_STRING_TABLE, - HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ); - if( name ) - { - value = std::string( name ); - } + value = std::string(name); } break; } case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT: { - if( impl.mController ) + const char* name = Text::GetVerticalAlignmentString(impl.mController->GetVerticalAlignment()); + if(name) { - const char* name = Scripting::GetEnumerationName< Toolkit::Text::Layout::VerticalAlignment >( impl.mController->GetVerticalAlignment(), - VERTICAL_ALIGNMENT_STRING_TABLE, - VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ); - if( name ) - { - value = std::string( name ); - } + value = std::string(name); } break; } - case Toolkit::TextLabel::Property::TEXT_COLOR: + case Toolkit::TextLabel::Property::ENABLE_MARKUP: { - if ( impl.mController ) - { - value = impl.mController->GetDefaultColor(); - } + value = impl.mController->IsMarkupProcessorEnabled(); break; } - case Toolkit::TextLabel::Property::SHADOW_OFFSET: + case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: { - if ( impl.mController ) - { - value = impl.mController->GetShadowOffset(); - } + value = impl.mController->IsAutoScrollEnabled(); break; } - case Toolkit::TextLabel::Property::SHADOW_COLOR: + case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE: { - if ( impl.mController ) + if(impl.mTextScroller) { - value = impl.mController->GetShadowColor(); + const char* mode = Scripting::GetEnumerationName(impl.mTextScroller->GetStopMode(), + AUTO_SCROLL_STOP_MODE_TABLE, + AUTO_SCROLL_STOP_MODE_TABLE_COUNT); + if(mode) + { + value = std::string(mode); + } } break; } - case Toolkit::TextLabel::Property::UNDERLINE_COLOR: + case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED: { - if ( impl.mController ) + if(impl.mTextScroller) { - value = impl.mController->GetUnderlineColor(); + value = impl.mTextScroller->GetSpeed(); } break; } - case Toolkit::TextLabel::Property::UNDERLINE_ENABLED: + case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT: { - if ( impl.mController ) + if(impl.mTextScroller) { - value = impl.mController->IsUnderlineEnabled(); + value = impl.mTextScroller->GetLoopCount(); } break; } - case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY: { - if ( impl.mController ) + if(impl.mTextScroller) { - value = impl.mController->GetUnderlineHeight(); + value = impl.mTextScroller->GetLoopDelay(); } break; } - case Toolkit::TextLabel::Property::ENABLE_MARKUP: + case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP: { - if( impl.mController ) + if(impl.mTextScroller) { - value = impl.mController->IsMarkupProcessorEnabled(); + value = impl.mTextScroller->GetGap(); } break; } - case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: + case Toolkit::TextLabel::Property::LINE_SPACING: { - if( impl.mController ) - { - value = impl.mController->IsAutoScrollEnabled(); - } + value = impl.mController->GetDefaultLineSpacing(); break; } - case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE: + case Toolkit::TextLabel::Property::UNDERLINE: { - if( impl.mTextScroller ) - { - const char* mode = Scripting::GetEnumerationName< Toolkit::DevelTextLabel::AutoScrollStopMode::Type >( impl.mTextScroller->GetStopMode(), - AUTO_SCROLL_STOP_MODE_TABLE, - AUTO_SCROLL_STOP_MODE_TABLE_COUNT ); - if( mode ) - { - value = std::string( mode ); - } - } + GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT); break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED: + case Toolkit::TextLabel::Property::SHADOW: { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetSpeed(); - } + GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT); break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT: + case Toolkit::TextLabel::Property::EMBOSS: { - if( impl.mController ) - { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetLoopCount(); - } - } + GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT); break; } - case Toolkit::DevelTextLabel::Property::AUTO_SCROLL_LOOP_DELAY: + case Toolkit::TextLabel::Property::OUTLINE: { - if( impl.mController ) - { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetLoopDelay(); - } - } + GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT); break; } - case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP: + case Toolkit::TextLabel::Property::PIXEL_SIZE: { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetGap(); - } + value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE); break; } - case Toolkit::TextLabel::Property::LINE_SPACING: + case Toolkit::TextLabel::Property::ELLIPSIS: { - if( impl.mController ) - { - value = impl.mController->GetDefaultLineSpacing(); - } + value = impl.mController->IsTextElideEnabled(); break; } - case Toolkit::TextLabel::Property::UNDERLINE: + case Toolkit::TextLabel::Property::LINE_WRAP_MODE: { - GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); + value = impl.mController->GetLineWrapMode(); break; } - case Toolkit::TextLabel::Property::SHADOW: + case Toolkit::TextLabel::Property::LINE_COUNT: { - GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); + float width = label.GetProperty(Actor::Property::SIZE_WIDTH).Get(); + value = impl.mController->GetLineCount(width); break; } - case Toolkit::TextLabel::Property::EMBOSS: + case Toolkit::DevelTextLabel::Property::TEXT_DIRECTION: { - GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); + value = impl.mController->GetTextDirection(); break; } - case Toolkit::TextLabel::Property::OUTLINE: + case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT: { - GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); + value = impl.mController->GetVerticalLineAlignment(); break; } - case Toolkit::DevelTextLabel::Property::PIXEL_SIZE: + case Toolkit::DevelTextLabel::Property::BACKGROUND: { - if( impl.mController ) - { - value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ); - } + GetBackgroundProperties(impl.mController, value, Text::EffectStyle::DEFAULT); break; } - case Toolkit::DevelTextLabel::Property::ELLIPSIS: + case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT: { - if( impl.mController ) - { - value = impl.mController->IsTextElideEnabled(); - } + value = impl.mController->IsIgnoreSpacesAfterText(); break; } - case Toolkit::DevelTextLabel::Property::LINE_COUNT: + case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION: { - if( impl.mController ) - { - float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get(); - value = impl.mController->GetLineCount( width ); - } + value = impl.mController->IsMatchSystemLanguageDirection(); + break; + } + case Toolkit::DevelTextLabel::Property::TEXT_FIT: + { + const bool enabled = impl.mController->IsTextFitEnabled(); + const float minSize = impl.mController->GetTextFitMinSize(); + const float maxSize = impl.mController->GetTextFitMaxSize(); + const float stepSize = impl.mController->GetTextFitStepSize(); + + Property::Map map; + map.Insert(TEXT_FIT_ENABLE_KEY, enabled); + map.Insert(TEXT_FIT_MIN_SIZE_KEY, minSize); + map.Insert(TEXT_FIT_MAX_SIZE_KEY, maxSize); + map.Insert(TEXT_FIT_STEP_SIZE_KEY, stepSize); + map.Insert(TEXT_FIT_FONT_SIZE_TYPE_KEY, "pointSize"); + + value = map; + break; + } + case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: + { + value = impl.mController->GetDefaultLineSize(); + break; + } + case Toolkit::DevelTextLabel::Property::FONT_SIZE_SCALE: + { + value = impl.mController->GetFontSizeScale(); break; } } @@ -752,47 +723,99 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde return value; } +bool TextLabel::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor) +{ + Dali::BaseHandle handle(object); + + bool connected(true); + Toolkit::TextLabel label = Toolkit::TextLabel::DownCast(handle); + + if(0 == strcmp(signalName.c_str(), SIGNAL_ANCHOR_CLICKED)) + { + if(label) + { + Internal::TextLabel& labelImpl(GetImpl(label)); + labelImpl.AnchorClickedSignal().Connect(tracker, functor); + } + } + else + { + // signalName does not match any signal + connected = false; + } + + return connected; +} + +DevelTextLabel::AnchorClickedSignalType& TextLabel::AnchorClickedSignal() +{ + return mAnchorClickedSignal; +} + void TextLabel::OnInitialize() { Actor self = Self(); - mController = Text::Controller::New( this ); + Property::Map propertyMap; + propertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT); - // When using the vector-based rendering, the size of the GLyphs are different - TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH; - mController->SetGlyphType( glyphType ); + mVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap); + DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual); + + TextVisual::SetAnimatableTextColorProperty(mVisual, Toolkit::TextLabel::Property::TEXT_COLOR); + + mController = TextVisual::GetController(mVisual); + DALI_ASSERT_DEBUG(mController && "Invalid Text Controller") + + mController->SetControlInterface(this); + mController->SetAnchorControlInterface(this); // Use height-for-width negotiation by default - self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); - self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT ); + self.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH); + self.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT); + + // Enable highlightability + self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true); // Enable the text ellipsis. - mController->SetTextElideEnabled( true ); // If false then text larger than control will overflow + mController->SetTextElideEnabled(true); // If false then text larger than control will overflow + + // Sets layoutDirection value + Dali::Stage stage = Dali::Stage::GetCurrent(); + Dali::LayoutDirection::Type layoutDirection = static_cast(stage.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); + mController->SetLayoutDirection(layoutDirection); + + // Forward input events to controller + EnableGestureDetection(static_cast(GestureType::TAP)); + GetTapGestureDetector().SetMaximumTapsRequired(1); Layout::Engine& engine = mController->GetLayoutEngine(); - engine.SetCursorWidth( 0u ); // Do not layout space for the cursor. + engine.SetCursorWidth(0u); // Do not layout space for the cursor. - self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect ); + DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) { + return std::unique_ptr( + new AccessibleImpl(actor, Dali::Accessibility::Role::LABEL)); + }); } -void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) +void TextLabel::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n"); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n"); - switch ( change ) + switch(change) { case StyleChange::DEFAULT_FONT_CHANGE: { // Property system did not set the font so should update it. - const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily(); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() ); - mController->UpdateAfterFontChange( newFont ); + const std::string& newFont = GetImpl(styleManager).GetDefaultFontFamily(); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str()); + mController->UpdateAfterFontChange(newFont); RelayoutRequest(); break; } case StyleChange::DEFAULT_FONT_SIZE_CHANGE: { - GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) ); + GetImpl(styleManager).ApplyThemeStyle(Toolkit::Control(GetOwner())); RelayoutRequest(); break; } @@ -804,134 +827,227 @@ void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange:: } // Up call to Control - Control::OnStyleChange( styleManager, change ); + Control::OnStyleChange(styleManager, change); } -Vector3 TextLabel::GetNaturalSize() +void TextLabel::OnTap(const TapGesture& gesture) { - return mController->GetNaturalSize(); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnTap %p\n", mController.Get()); + + // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); + const Vector2& localPoint = gesture.GetLocalPoint(); + mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top); } -float TextLabel::GetHeightForWidth( float width ) +void TextLabel::AnchorClicked(const std::string& href) { - Padding padding; - Self().GetPadding( padding ); - return mController->GetHeightForWidth( width ) + padding.top + padding.bottom; + Dali::Toolkit::TextLabel handle(GetOwner()); + mAnchorClickedSignal.Emit(handle, href.c_str(), href.length()); } -void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container ) +Vector3 TextLabel::GetNaturalSize() { - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout\n" ); + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); - Padding padding; - Self().GetPadding( padding ); - Vector2 contentSize( size.x - ( padding.left + padding.right ), size.y - ( padding.top + padding.bottom ) ); + Vector3 naturalSize = mController->GetNaturalSize(); + naturalSize.width += (padding.start + padding.end); + naturalSize.height += (padding.top + padding.bottom); + return naturalSize; +} - const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize ); +float TextLabel::GetHeightForWidth(float width) +{ + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); - if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) ) || - !mRenderer ) + return mController->GetHeightForWidth(width) + padding.top + padding.bottom; +} + +void TextLabel::OnPropertySet(Property::Index index, const Property::Value& propertyValue) +{ + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index); + + switch(index) { - if( !mRenderer ) + case Toolkit::TextLabel::Property::TEXT_COLOR: { - mRenderer = Text::Backend::Get().NewRenderer( mRenderingBackend ); + const Vector4& textColor = propertyValue.Get(); + if(mController->GetDefaultColor() != textColor) + { + mController->SetDefaultColor(textColor); + mTextUpdateNeeded = true; + } + break; + } + default: + { + Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties + break; } - RenderText(); } } -void TextLabel::RequestTextRelayout() +void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container) { - RelayoutRequest(); -} + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout\n"); -void TextLabel::RenderText() -{ - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::RenderText IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this ); + Extents padding; + padding = Self().GetProperty(Toolkit::Control::Property::PADDING); - Actor self = Self(); - Actor renderableActor; + Vector2 contentSize(size.x - (padding.start + padding.end), size.y - (padding.top + padding.bottom)); + + if(mController->IsTextFitEnabled()) + { + mController->FitPointSizeforLayout(contentSize); + mController->SetTextFitContentSize(contentSize); + } - float alignmentOffset = 0.f; - if( mRenderer ) + // Support Right-To-Left + Dali::LayoutDirection::Type layoutDirection; + if(mController->IsMatchSystemLanguageDirection()) { - renderableActor = mRenderer->Render( mController->GetView(), - alignmentOffset, - DepthIndex::CONTENT ); + layoutDirection = static_cast(DevelWindow::Get(Self()).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); } + else + { + layoutDirection = static_cast(Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); + } + const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection); - if( renderableActor != mRenderableActor ) + if((Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType)) || mTextUpdateNeeded) { - UnparentAndReset( mRenderableActor ); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", (mController->IsAutoScrollEnabled()) ? "true" : "false", this); - if( renderableActor ) + // Update the visual + TextVisual::EnableRendererUpdate(mVisual); + + // Support Right-To-Left of padding + if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection) { - const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition(); - Padding padding; - self.GetPadding( padding ); - renderableActor.SetPosition( scrollOffset.x + alignmentOffset + padding.left, scrollOffset.y + padding.top ); + std::swap(padding.start, padding.end); + } + + // Calculate the size of the visual that can fit the text + Size layoutSize = mController->GetTextModel()->GetLayoutSize(); + layoutSize.x = contentSize.x; - self.Add( renderableActor ); + const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset(); + if(shadowOffset.y > Math::MACHINE_EPSILON_1) + { + layoutSize.y += shadowOffset.y; } - mRenderableActor = renderableActor; - if ( mController->IsAutoScrollEnabled() ) + float outlineWidth = mController->GetTextModel()->GetOutlineWidth(); + layoutSize.y += outlineWidth * 2.0f; + layoutSize.y = std::min(layoutSize.y, contentSize.y); + + // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment. + Vector2 alignmentOffset; + alignmentOffset.x = 0.0f; + alignmentOffset.y = (contentSize.y - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()]; + + Property::Map visualTransform; + visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, layoutSize) + .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2(padding.start, padding.top) + alignmentOffset) + .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) + .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN); + mVisual.SetTransformAndSize(visualTransform, size); + + if(mController->IsAutoScrollEnabled()) { SetUpAutoScrolling(); } + + mTextUpdateNeeded = false; } } +void TextLabel::RequestTextRelayout() +{ + RelayoutRequest(); + // Signal that a Relayout may be needed +} + void TextLabel::SetUpAutoScrolling() { - const Size& controlSize = mController->GetView().GetControlSize(); - const Size offScreenSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only. - const float alignmentOffset = mController->GetAutoScrollLineAlignment(); - const Text::CharacterDirection direction = mController->GetAutoScrollDirection(); + const Size& controlSize = mController->GetView().GetControlSize(); + const Size textNaturalSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only. + const Text::CharacterDirection direction = mController->GetAutoScrollDirection(); - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling alignmentOffset[%f] offScreenSize[%f,%f] controlSize[%f,%f]\n", - alignmentOffset, offScreenSize.x,offScreenSize.y , controlSize.x,controlSize.y ); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n", textNaturalSize.x, textNaturalSize.y, controlSize.x, controlSize.y); - if ( !mTextScroller ) + if(!mTextScroller) { - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n" ); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n"); // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults - mTextScroller = Text::TextScroller::New( *this ); + mTextScroller = Text::TextScroller::New(*this); } - mTextScroller->SetParameters( mRenderableActor, controlSize, offScreenSize, direction, alignmentOffset, mController->GetHorizontalAlignment() ); - Actor self = Self(); - self.Add( mTextScroller->GetScrollingText() ); - self.Add( mTextScroller->GetSourceCamera() ); -} + // Calculate the actual gap before scrolling wraps. + int textPadding = std::max(controlSize.x - textNaturalSize.x, 0.0f); + float wrapGap = std::max(mTextScroller->GetGap(), textPadding); + Vector2 textureSize = textNaturalSize + Vector2(wrapGap, 0.0f); // Add the gap as a part of the texture -void TextLabel::OnStageConnect( Dali::Actor actor ) -{ - if ( mHasBeenStaged ) - { - RenderText(); - } - else + // Create a texture of the text for scrolling + Size verifiedSize = textureSize; + const int maxTextureSize = Dali::GetMaxTextureSize(); + + //if the texture size width exceed maxTextureSize, modify the visual model size and enabled the ellipsis + bool actualellipsis = mController->IsTextElideEnabled(); + if(verifiedSize.width > maxTextureSize) { - mHasBeenStaged = true; + verifiedSize.width = maxTextureSize; + if(textNaturalSize.width > maxTextureSize) + { + mController->SetTextElideEnabled(true); + } + GetHeightForWidth(maxTextureSize); + wrapGap = std::max(maxTextureSize - textNaturalSize.width, 0.0f); } + + Text::TypesetterPtr typesetter = Text::Typesetter::New(mController->GetTextModel()); + + PixelData data = typesetter->Render(verifiedSize, mController->GetTextDirection(), Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888); // ignore the horizontal alignment + Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, + data.GetPixelFormat(), + data.GetWidth(), + data.GetHeight()); + texture.Upload(data); + + TextureSet textureSet = TextureSet::New(); + textureSet.SetTexture(0u, texture); + + // Filter mode needs to be set to linear to produce better quality while scaling. + Sampler sampler = Sampler::New(); + sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR); + sampler.SetWrapMode(Dali::WrapMode::DEFAULT, Dali::WrapMode::REPEAT, Dali::WrapMode::DEFAULT); // Wrap the texture in the x direction + textureSet.SetSampler(0u, sampler); + + // Set parameters for scrolling + Renderer renderer = static_cast(GetImplementation(mVisual)).GetRenderer(); + mTextScroller->SetParameters(Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment()); + mController->SetTextElideEnabled(actualellipsis); } void TextLabel::ScrollingFinished() { // Pure Virtual from TextScroller Interface - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n"); - mController->SetAutoScrollEnabled( false ); - mController->SetTextElideEnabled( true ); + DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n"); + mController->SetAutoScrollEnabled(false); RequestTextRelayout(); } TextLabel::TextLabel() -: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ), - mRenderingBackend( DEFAULT_RENDERING_BACKEND ), - mHasBeenStaged( false ) +: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)), + mRenderingBackend(DEFAULT_RENDERING_BACKEND), + mTextUpdateNeeded(false) { } @@ -939,6 +1055,169 @@ TextLabel::~TextLabel() { } +std::string TextLabel::AccessibleImpl::GetNameRaw() +{ + auto slf = Toolkit::TextLabel::DownCast(Self()); + return slf.GetProperty(Toolkit::TextLabel::Property::TEXT).Get(); +} + +Property::Index TextLabel::AccessibleImpl::GetNamePropertyIndex() +{ + return Toolkit::TextLabel::Property::TEXT; +} + +std::string TextLabel::AccessibleImpl::GetText(size_t startOffset, + size_t endOffset) +{ + if(endOffset <= startOffset) + return {}; + + auto slf = Toolkit::TextLabel::DownCast(Self()); + auto txt = + slf.GetProperty(Toolkit::TextLabel::Property::TEXT).Get(); + + if(startOffset > txt.size() || endOffset > txt.size()) + return {}; + + return txt.substr(startOffset, endOffset - startOffset); +} + +size_t TextLabel::AccessibleImpl::GetCharacterCount() +{ + auto slf = Toolkit::TextLabel::DownCast(Self()); + auto txt = + slf.GetProperty(Toolkit::TextLabel::Property::TEXT).Get(); + + return txt.size(); +} + +size_t TextLabel::AccessibleImpl::GetCaretOffset() +{ + return {}; +} + +bool TextLabel::AccessibleImpl::SetCaretOffset(size_t offset) +{ + return {}; +} + +Dali::Accessibility::Range TextLabel::AccessibleImpl::GetTextAtOffset( + size_t offset, Dali::Accessibility::TextBoundary boundary) +{ + auto slf = Toolkit::TextLabel::DownCast(Self()); + auto txt = slf.GetProperty(Toolkit::TextLabel::Property::TEXT).Get(); + auto txt_size = txt.size(); + + auto range = Dali::Accessibility::Range{}; + + switch(boundary) + { + case Dali::Accessibility::TextBoundary::CHARACTER: + { + if(offset < txt_size) + { + range.content = txt[offset]; + range.startOffset = offset; + range.endOffset = offset + 1; + } + } + break; + case Dali::Accessibility::TextBoundary::WORD: + case Dali::Accessibility::TextBoundary::LINE: + { + auto txt_c_string = txt.c_str(); + auto breaks = std::vector(txt_size, 0); + if(boundary == Dali::Accessibility::TextBoundary::WORD) + Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t*)txt_c_string, txt_size, "", breaks.data()); + else + Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t*)txt_c_string, txt_size, "", breaks.data()); + auto index = 0u; + auto counter = 0u; + while(index < txt_size && counter <= offset) + { + auto start = index; + if(breaks[index]) + { + while(breaks[index]) + index++; + counter++; + } + else + { + if(boundary == Dali::Accessibility::TextBoundary::WORD) + index++; + if(boundary == Dali::Accessibility::TextBoundary::LINE) + counter++; + } + if((counter > 0) && ((counter - 1) == offset)) + { + range.content = txt.substr(start, index - start + 1); + range.startOffset = start; + range.endOffset = index + 1; + } + if(boundary == Dali::Accessibility::TextBoundary::LINE) + index++; + } + } + break; + case Dali::Accessibility::TextBoundary::SENTENCE: + { + /* not supported by efl */ + } + break; + case Dali::Accessibility::TextBoundary::PARAGRAPH: + { + /* Paragraph is not supported by libunibreak library */ + } + break; + default: + break; + } + + return range; +} + +Dali::Accessibility::Range +TextLabel::AccessibleImpl::GetSelection(size_t selectionNum) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if(selectionNum > 0) + return {}; + + auto slf = Toolkit::TextLabel::DownCast(Self()); + auto ctrl = Dali::Toolkit::GetImpl(slf).getController(); + std::string ret; + ctrl->RetrieveSelection(ret); + auto r = ctrl->GetSelectionIndexes(); + + return {static_cast(r.first), static_cast(r.second), ret}; +} + +bool TextLabel::AccessibleImpl::RemoveSelection(size_t selectionNum) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if(selectionNum > 0) + return false; + + auto slf = Toolkit::TextLabel::DownCast(Self()); + Dali::Toolkit::GetImpl(slf).getController()->SetSelection(0, 0); + return true; +} + +bool TextLabel::AccessibleImpl::SetSelection(size_t selectionNum, + size_t startOffset, + size_t endOffset) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if(selectionNum > 0) + return false; + + auto slf = Toolkit::TextLabel::DownCast(Self()); + Dali::Toolkit::GetImpl(slf).getController()->SetSelection(startOffset, + endOffset); + return true; +} + } // namespace Internal } // namespace Toolkit