[AT-SPI] Squashed implementation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-controls / text-label-impl.cpp
index 1cdb0f8..4699878 100755 (executable)
@@ -62,33 +62,29 @@ namespace Internal
 
 namespace
 {
-  const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND;
-
-  /**
-   * @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" );
-}
+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[] =
@@ -145,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()
@@ -275,101 +338,61 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
       }
       case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
       {
-        if( !impl.mTextScroller )
-        {
-          impl.mTextScroller = Text::TextScroller::New( impl );
-        }
-        Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode();
+        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 ) )
+                                                                                               AUTO_SCROLL_STOP_MODE_TABLE,
+                                                                                               AUTO_SCROLL_STOP_MODE_TABLE_COUNT,
+                                                                                               stopMode ) )
         {
-            impl.mTextScroller->SetStopMode( stopMode );
+          textScroller->SetStopMode( stopMode );
         }
         break;
       }
       case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
       {
-        if( !impl.mTextScroller )
-        {
-          impl.mTextScroller = Text::TextScroller::New( impl );
-        }
-        impl.mTextScroller->SetSpeed( value.Get<int>() );
+        impl.GetTextScroller()->SetSpeed( value.Get<int>() );
         break;
       }
       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
       {
-        if( !impl.mTextScroller )
-        {
-          impl.mTextScroller = Text::TextScroller::New( impl );
-        }
-        impl.mTextScroller->SetLoopCount( value.Get<int>() );
+        impl.GetTextScroller()->SetLoopCount( value.Get<int>() );
         break;
       }
       case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
       {
-         if( !impl.mTextScroller )
-        {
-          impl.mTextScroller = Text::TextScroller::New( impl );
-        }
-        impl.mTextScroller->SetLoopDelay( value.Get<float>() );
+        impl.GetTextScroller()->SetLoopDelay( value.Get<float>() );
         break;
       }
       case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
       {
-        if( !impl.mTextScroller )
-        {
-          impl.mTextScroller = Text::TextScroller::New( impl );
-        }
-        impl.mTextScroller->SetGap( value.Get<float>() );
+        impl.GetTextScroller()->SetGap( value.Get<float>() );
         break;
       }
       case Toolkit::TextLabel::Property::LINE_SPACING:
       {
         const float lineSpacing = value.Get<float>();
-
-        // Don't trigger anything if the line spacing didn't change
-        if( impl.mController->SetDefaultLineSpacing( lineSpacing ) )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSpacing( lineSpacing ) || impl.mTextUpdateNeeded;
         break;
       }
       case Toolkit::TextLabel::Property::UNDERLINE:
       {
-        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
-        if( update )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ) || impl.mTextUpdateNeeded;
         break;
       }
       case Toolkit::TextLabel::Property::SHADOW:
       {
-        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
-        if( update )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT ) || impl.mTextUpdateNeeded;
         break;
       }
       case Toolkit::TextLabel::Property::EMBOSS:
       {
-        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
-        if( update )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT ) || impl.mTextUpdateNeeded;
         break;
       }
       case Toolkit::TextLabel::Property::OUTLINE:
       {
-        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
-        if( update )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT ) || impl.mTextUpdateNeeded;
         break;
       }
       case Toolkit::TextLabel::Property::PIXEL_SIZE:
@@ -419,11 +442,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
       }
       case Toolkit::DevelTextLabel::Property::BACKGROUND:
       {
-        const bool update = SetBackgroundProperties( 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::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
@@ -438,80 +457,13 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
       }
       case Toolkit::DevelTextLabel::Property::TEXT_FIT:
       {
-        const Property::Map& propertiesMap = value.Get<Property::Map>();
-
-        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;
-
-        if ( !propertiesMap.Empty() )
-        {
-          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;
-              }
-            }
-          }
-
-          impl.mController->SetTextFitEnabled( enabled );
-          if( isMinSizeSet )
-          {
-            impl.mController->SetTextFitMinSize( minSize, type );
-          }
-          if( isMaxSizeSet )
-          {
-            impl.mController->SetTextFitMaxSize( maxSize, type );
-          }
-          if( isStepSizeSet )
-          {
-            impl.mController->SetTextFitStepSize( stepSize, type );
-          }
-        }
+        ParseTextFitProperty(impl.mController, value.GetMap());
         break;
       }
       case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
       {
         const float lineSize = value.Get<float>();
-
-        if( impl.mController->SetDefaultLineSize( lineSize ) )
-        {
-          impl.mTextUpdateNeeded = true;
-        }
+        impl.mTextUpdateNeeded = impl.mController->SetDefaultLineSize( lineSize ) || impl.mTextUpdateNeeded;
         break;
       }
     }
@@ -527,6 +479,8 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
   }
 }
 
+Text::ControllerPtr TextLabel::getController() { return mController; }
+
 Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
 {
   Property::Value value;
@@ -1015,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<size_t>(r.first), static_cast<size_t>(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