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=4699878713e0313a2998defecde3ba68fc5d61ac;hp=94957db9400ae4f65a3f0a83337f6fbadba2da07;hb=8a647e87a01c5c78451653c1264a9eea81ac9b20;hpb=9240aafab3932a3b945bdff63df35efd4e3ceb02 diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp old mode 100644 new mode 100755 index 94957db..4699878 --- 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) 2020 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,14 +19,17 @@ #include // EXTERNAL INCLUDES +#include #include +#include #include #include +#include #include // INTERNAL INCLUDES -#include #include +#include #include #include #include @@ -44,6 +47,8 @@ #include #include +#include + using namespace Dali::Toolkit::Text; namespace Dali @@ -57,14 +62,29 @@ 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"); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] = @@ -83,7 +103,6 @@ BaseHandle Create() // 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 ) @@ -91,12 +110,6 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "pointSize", 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, "unusedPropertyTextColor", VECTOR4, UNUSED_PROPERTY_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 ) @@ -113,6 +126,14 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopDelay", 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_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 ) @@ -120,6 +141,73 @@ DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textCol DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3 ) DALI_TYPE_REGISTRATION_END() +/// 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< bool >(); + } + 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< float >(); + 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< float >(); + 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< float >(); + 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< std::string >() ) + { + 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() @@ -144,16 +232,16 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr if( label ) { 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: { - DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__); - int backend = value.Get< int >(); #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 } @@ -163,32 +251,23 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr impl.mRenderingBackend = backend; 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< std::string >() ); break; } case Toolkit::TextLabel::Property::FONT_FAMILY: { - if( impl.mController ) - { - const std::string& fontFamily = value.Get< std::string >(); + const std::string& fontFamily = value.Get< std::string >(); - 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: @@ -198,298 +277,210 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr } case Toolkit::TextLabel::Property::POINT_SIZE: { - if( impl.mController ) - { - const float pointSize = value.Get< float >(); + const float pointSize = value.Get< float >(); - 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< bool >() ); break; } case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT: { - if( impl.mController ) + Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set + if( Text::GetHorizontalAlignmentEnumeration( value, alignment ) ) { - Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set - if( Text::GetHorizontalAlignmentEnumeration( value, 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< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set + if( Text::GetVerticalAlignmentEnumeration( value, alignment ) ) { - Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set - if( Text::GetVerticalAlignmentEnumeration( value, alignment ) ) - { - impl.mController->SetVerticalAlignment( alignment ); - } + impl.mController->SetVerticalAlignment( alignment ); } break; } - - case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR: + case Toolkit::TextLabel::Property::ENABLE_MARKUP: { - label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, value ); - impl.mTextUpdateNeeded = true; + 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 ) - { - impl.mController->SetShadowOffset( shadowOffset ); - impl.mTextUpdateNeeded = true; - } + // 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->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< Toolkit::TextLabel::AutoScrollStopMode::Type >( 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.mTextUpdateNeeded = true; - } + 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.mTextUpdateNeeded = true; - } - } + 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.mTextUpdateNeeded = true; - } - } + 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.mTextUpdateNeeded = true; - } - } + 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::TextLabel::Property::AUTO_SCROLL_STOP_MODE: + case Toolkit::TextLabel::Property::UNDERLINE: { - if( !impl.mTextScroller ) - { - impl.mTextScroller = Text::TextScroller::New( impl ); - } - Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode(); - if( Scripting::GetEnumerationProperty< Toolkit::TextLabel::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::TextLabel::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< 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.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.mTextUpdateNeeded = true; - } + 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< Text::LineWrap::Mode >( -1 ) ); // Set to invalid value to ensure a valid mode does get set + if( GetLineWrapModeEnumeration( value, lineWrapMode ) ) { - impl.mTextUpdateNeeded = true; + 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.mTextUpdateNeeded = true; + 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.mTextUpdateNeeded = true; - } + 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.mTextUpdateNeeded = true; - } + impl.mController->SetIgnoreSpacesAfterText(value.Get< bool >()); break; } - case Toolkit::TextLabel::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< bool >()); break; } - case Toolkit::TextLabel::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 ); - - impl.mController->SetTextElideEnabled( ellipsis ); - } + ParseTextFitProperty(impl.mController, value.GetMap()); break; } - case Toolkit::TextLabel::Property::LINE_WRAP_MODE: + case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: { - if( impl.mController ) - { - Text::LineWrap::Mode lineWrapMode( static_cast< Text::LineWrap::Mode >( -1 ) ); // Set to invalid value to ensure a valid mode does get set - if( GetLineWrapModeEnumeration( value, lineWrapMode ) ) - { - DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode ); - impl.mController->SetLineWrapMode( lineWrapMode ); - } - } + const float lineSize = value.Get(); + impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize( lineSize ) || impl.mTextUpdateNeeded; 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(); + } } } +Text::ControllerPtr TextLabel::getController() { return mController; } + Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index ) { Property::Value value; @@ -499,31 +490,25 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde if( label ) { 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: { - DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__); - 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: @@ -533,104 +518,41 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } 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() ); + const char* name = Text::GetHorizontalAlignmentString( impl.mController->GetHorizontalAlignment() ); - if ( 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 ) - { - value = std::string( name ); - } - } - break; - } - case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR: - { - value = label.GetProperty( Toolkit::TextLabel::Property::TEXT_COLOR ); - break; - } - case Toolkit::TextLabel::Property::SHADOW_OFFSET: - { - if ( impl.mController ) - { - value = impl.mController->GetShadowOffset(); - } - break; - } - case Toolkit::TextLabel::Property::SHADOW_COLOR: - { - if ( impl.mController ) - { - value = impl.mController->GetShadowColor(); - } - break; - } - case Toolkit::TextLabel::Property::UNDERLINE_COLOR: - { - if ( impl.mController ) - { - value = impl.mController->GetUnderlineColor(); - } - break; - } - case Toolkit::TextLabel::Property::UNDERLINE_ENABLED: - { - if ( impl.mController ) + if ( name ) { - value = impl.mController->IsUnderlineEnabled(); + value = std::string( name ); } break; } - case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT: { - if ( impl.mController ) + const char* name = Text::GetVerticalAlignmentString( impl.mController->GetVerticalAlignment() ); + if( name ) { - value = impl.mController->GetUnderlineHeight(); + value = std::string( name ); } break; } case Toolkit::TextLabel::Property::ENABLE_MARKUP: { - if( impl.mController ) - { - value = impl.mController->IsMarkupProcessorEnabled(); - } + value = impl.mController->IsMarkupProcessorEnabled(); break; } case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL: { - if( impl.mController ) - { - value = impl.mController->IsAutoScrollEnabled(); - } + value = impl.mController->IsAutoScrollEnabled(); break; } case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE: @@ -649,7 +571,6 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED: { - TextLabel& impl( GetImpl( label ) ); if ( impl.mTextScroller ) { value = impl.mTextScroller->GetSpeed(); @@ -658,31 +579,22 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT: { - if( impl.mController ) + if ( impl.mTextScroller ) { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetLoopCount(); - } + value = impl.mTextScroller->GetLoopCount(); } break; } case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY: { - if( impl.mController ) + if ( impl.mTextScroller ) { - TextLabel& impl( GetImpl( label ) ); - if ( impl.mTextScroller ) - { - value = impl.mTextScroller->GetLoopDelay(); - } + value = impl.mTextScroller->GetLoopDelay(); } break; } case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP: { - TextLabel& impl( GetImpl( label ) ); if ( impl.mTextScroller ) { value = impl.mTextScroller->GetGap(); @@ -691,10 +603,7 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } case Toolkit::TextLabel::Property::LINE_SPACING: { - if( impl.mController ) - { - value = impl.mController->GetDefaultLineSpacing(); - } + value = impl.mController->GetDefaultLineSpacing(); break; } case Toolkit::TextLabel::Property::UNDERLINE: @@ -719,35 +628,70 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } case Toolkit::TextLabel::Property::PIXEL_SIZE: { - if( impl.mController ) - { - value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ); - } + value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ); break; } case Toolkit::TextLabel::Property::ELLIPSIS: { - if( impl.mController ) - { - value = impl.mController->IsTextElideEnabled(); - } + value = impl.mController->IsTextElideEnabled(); break; } case Toolkit::TextLabel::Property::LINE_WRAP_MODE: { - if( impl.mController ) - { - value = impl.mController->GetLineWrapMode(); - } + value = impl.mController->GetLineWrapMode(); break; } case Toolkit::TextLabel::Property::LINE_COUNT: { - if( impl.mController ) - { - float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get(); - value = impl.mController->GetLineCount( width ); - } + float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get(); + value = impl.mController->GetLineCount( width ); + break; + } + case Toolkit::DevelTextLabel::Property::TEXT_DIRECTION: + { + value = impl.mController->GetTextDirection(); + break; + } + case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT: + { + value = impl.mController->GetVerticalLineAlignment(); + break; + } + case Toolkit::DevelTextLabel::Property::BACKGROUND: + { + GetBackgroundProperties( impl.mController, value, Text::EffectStyle::DEFAULT ); + break; + } + case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT: + { + value = impl.mController->IsIgnoreSpacesAfterText(); + break; + } + case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION: + { + 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; } } @@ -769,10 +713,9 @@ void TextLabel::OnInitialize() TextVisual::SetAnimatableTextColorProperty( mVisual, Toolkit::TextLabel::Property::TEXT_COLOR ); mController = TextVisual::GetController(mVisual); - if( mController ) - { - mController->SetControlInterface(this); - } + DALI_ASSERT_DEBUG( mController && "Invalid Text Controller") + + mController->SetControlInterface(this); // Use height-for-width negotiation by default self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); @@ -781,6 +724,11 @@ void TextLabel::OnInitialize() // Enable the text ellipsis. 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 ); + Layout::Engine& engine = mController->GetLayoutEngine(); engine.SetCursorWidth( 0u ); // Do not layout space for the cursor. } @@ -837,7 +785,7 @@ float TextLabel::GetHeightForWidth( float width ) return mController->GetHeightForWidth( width ) + padding.top + padding.bottom; } -void TextLabel::OnPropertySet( Property::Index index, Property::Value propertyValue ) +void TextLabel::OnPropertySet( Property::Index index, const Property::Value& propertyValue ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index ); @@ -870,7 +818,23 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container ) Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) ); - const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize ); + if( mController->IsTextFitEnabled() ) + { + mController->FitPointSizeforLayout( contentSize ); + mController->SetTextFitContentSize( contentSize ); + } + + // Support Right-To-Left + Dali::LayoutDirection::Type layoutDirection; + if( mController->IsMatchSystemLanguageDirection() ) + { + 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( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) ) || mTextUpdateNeeded ) @@ -881,16 +845,34 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container ) TextVisual::EnableRendererUpdate( mVisual ); // Support Right-To-Left of padding - Dali::LayoutDirection::Type layoutDirection = static_cast( Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get() ); if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection ) { 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; + + const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset(); + if ( shadowOffset.y > Math::MACHINE_EPSILON_1 ) + { + layoutSize.y += shadowOffset.y; + } + + 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, contentSize ) + 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 ) ) + .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 ); @@ -908,6 +890,7 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container ) void TextLabel::RequestTextRelayout() { RelayoutRequest(); + // Signal that a Relayout may be needed } void TextLabel::SetUpAutoScrolling() @@ -937,6 +920,7 @@ void TextLabel::SetUpAutoScrolling() 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 ) { verifiedSize.width = maxTextureSize; @@ -950,7 +934,7 @@ void TextLabel::SetUpAutoScrolling() Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() ); - PixelData data = typesetter->Render( verifiedSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment + 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(), @@ -969,6 +953,7 @@ void TextLabel::SetUpAutoScrolling() // 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() @@ -976,7 +961,6 @@ void TextLabel::ScrollingFinished() // Pure Virtual from TextScroller Interface DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n"); mController->SetAutoScrollEnabled( false ); - mController->SetTextElideEnabled( true ); RequestTextRelayout(); } @@ -985,12 +969,174 @@ TextLabel::TextLabel() mRenderingBackend( DEFAULT_RENDERING_BACKEND ), mTextUpdateNeeded( false ) { + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::LABEL ) ); + } ); } TextLabel::~TextLabel() { } +std::string TextLabel::AccessibleImpl::GetNameRaw() +{ + auto slf = Toolkit::TextLabel::DownCast( self ); + return slf.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get< std::string >(); +} + +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< std::string >(); + + 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< std::string >(); + + 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< std::string >(); + 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< char >( 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 - 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