Introduce REMOVE_FRONT_INSET, REMOVE_BACK_INSET Property 25/307025/17
authorANZ1217 <chihun.jeong@samsung.com>
Wed, 21 Feb 2024 05:39:52 +0000 (14:39 +0900)
committerANZ1217 <chihun.jeong@samsung.com>
Mon, 11 Mar 2024 07:45:49 +0000 (16:45 +0900)
Added new property to TextLabel

Example:
textLabel.SetProperty(DevelTextLabel::Property::REMOVE_FRONT_INSET, false);
textLabel.SetProperty(DevelTextLabel::Property::REMOVE_BACK_INSET, false);

When REMOVE_FRONT_INSET is set to false, the xBearing of first glyph won't be trimmed.
When REMOVE_BACK_INSET is set to false, the advance of last glyph won't be trimmed.

Change-Id: I169d87b9f83d3b204ea51601188982cda54cb9d0

automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/controls/text-controls/text-label-devel.cpp
dali-toolkit/devel-api/controls/text-controls/text-label-devel.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/text/controller/text-controller.cpp
dali-toolkit/internal/text/controller/text-controller.h
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h

index a45aa41..dd0b690 100644 (file)
@@ -80,6 +80,9 @@ const char* const PROPERTY_NAME_ELLIPSIS_POSITION    = "ellipsisPosition";
 const char* const PROPERTY_NAME_ANCHOR_COLOR         = "anchorColor";
 const char* const PROPERTY_NAME_ANCHOR_CLICKED_COLOR = "anchorClickedColor";
 
+const char* const PROPERTY_NAME_REMOVE_FRONT_INSET    = "removeFrontInset";
+const char* const PROPERTY_NAME_REMOVE_BACK_INSET     = "removeBackInset";
+
 const std::string  DEFAULT_FONT_DIR("/resources/fonts");
 const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
 
@@ -360,6 +363,8 @@ int UtcDaliToolkitTextLabelGetPropertyP(void)
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextLabel::Property::STRIKETHROUGH);
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_COLOR) == DevelTextLabel::Property::ANCHOR_COLOR);
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_CLICKED_COLOR) == DevelTextLabel::Property::ANCHOR_CLICKED_COLOR);
+  DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextLabel::Property::REMOVE_FRONT_INSET);
+  DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextLabel::Property::REMOVE_BACK_INSET);
 
   END_TEST;
 }
@@ -1019,6 +1024,18 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
   application.SendNotification();
   application.Render();
 
+  // Check Remove Front/Back Inset Property
+  DALI_TEST_CHECK(label.GetProperty<bool>(DevelTextLabel::Property::REMOVE_FRONT_INSET));
+  label.SetProperty(DevelTextLabel::Property::REMOVE_FRONT_INSET, false);
+  DALI_TEST_CHECK(!label.GetProperty<bool>(DevelTextLabel::Property::REMOVE_FRONT_INSET));
+
+  DALI_TEST_CHECK(label.GetProperty<bool>(DevelTextLabel::Property::REMOVE_BACK_INSET));
+  label.SetProperty(DevelTextLabel::Property::REMOVE_BACK_INSET, false);
+  DALI_TEST_CHECK(!label.GetProperty<bool>(DevelTextLabel::Property::REMOVE_BACK_INSET));
+
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
@@ -3323,4 +3340,40 @@ int utcDaliTextLabelGetTextBoundingRectangle(void)
   TestTextGeometryUtils::CheckRectGeometryResult(textBoundingRectangle, expectedTextBoundingRectangle);
 
   END_TEST;
+}
+
+int utcDaliTextLabelRemoveFrontInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextLabelRemoveFrontInset");
+
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK(label);
+
+  application.GetScene().Add(label);
+  application.SendNotification();
+  application.Render();
+
+  DevelTextLabel::SetRemoveFrontInset(label, false);
+  DALI_TEST_CHECK(!DevelTextLabel::IsRemoveFrontInset(label));
+
+  END_TEST;
+}
+
+int utcDaliTextLabelRemoveBackInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextLabelRemoveBackInset");
+
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK(label);
+
+  application.GetScene().Add(label);
+  application.SendNotification();
+  application.Render();
+
+  DevelTextLabel::SetRemoveBackInset(label, false);
+  DALI_TEST_CHECK(!DevelTextLabel::IsRemoveBackInset(label));
+
+  END_TEST;
 }
\ No newline at end of file
index 692aed8..48a4567 100644 (file)
@@ -65,6 +65,26 @@ bool IsTextFitArrayEnabled(TextLabel textLabel)
   return GetImpl(textLabel).IsTextFitArrayEnabled();
 }
 
+void SetRemoveFrontInset(TextLabel textLabel, const bool remove)
+{
+  GetImpl(textLabel).SetRemoveFrontInset(remove);
+}
+
+bool IsRemoveFrontInset(TextLabel textLabel)
+{
+  return GetImpl(textLabel).IsRemoveFrontInset();
+}
+
+void SetRemoveBackInset(TextLabel textLabel, const bool remove)
+{
+  GetImpl(textLabel).SetRemoveBackInset(remove);
+}
+
+bool IsRemoveBackInset(TextLabel textLabel)
+{
+  return GetImpl(textLabel).IsRemoveBackInset();
+}
+
 } // namespace DevelTextLabel
 
 } // namespace Toolkit
index 8771255..ed2e5d9 100644 (file)
@@ -218,6 +218,18 @@ enum Type
    * @note If there is a color attribute in the anchor tag, the markup attribute takes precedence.
    */
   ANCHOR_CLICKED_COLOR,
+
+  /**
+   * @brief Whether to trim the xBearing of first glyph of the text.
+   * @details Name "removeFrontInset", type Property::BOOLEAN.
+   */
+  REMOVE_FRONT_INSET,
+
+  /**
+   * @brief Whether to trim the advance of last glyph of the text.
+   * @details Name "removeBackInset", type Property::BOOLEAN.
+   */
+  REMOVE_BACK_INSET,
 };
 
 } // namespace Property
@@ -308,6 +320,38 @@ DALI_TOOLKIT_API std::vector<FitOption>& GetTextFitArray(TextLabel textLabel);
 DALI_TOOLKIT_API bool IsTextFitArrayEnabled(TextLabel textLabel);
 
 /**
+ * @brief Set removing front inset to text label.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @param[in] remove Whether front inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveFrontInset(TextLabel textLabel, const bool remove);
+
+/**
+ * @brief Whether front inset of text label is removed or not.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @return True if the front inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveFrontInset(TextLabel textLabel);
+
+/**
+ * @brief Set removing back inset to text label.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @param[in] remove Whether back inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveBackInset(TextLabel textLabel, const bool remove);
+
+/**
+ * @brief Whether back inset of text label is removed or not.
+ *
+ * @param[in] textLabel The instance of TextLabel.
+ * @return True if the back inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveBackInset(TextLabel textLabel);
+
+/**
  * @brief Anchor clicked signal type.
  *
  * @note Signal
index 262c5cc..5309e89 100644 (file)
@@ -144,6 +144,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "characterSpacing
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "relativeLineSize",             FLOAT,   RELATIVE_LINE_SIZE             )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "anchorColor",                  VECTOR4, ANCHOR_COLOR                   )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "anchorClickedColor",           VECTOR4, ANCHOR_CLICKED_COLOR           )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "removeFrontInset",             BOOLEAN, REMOVE_FRONT_INSET             )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "removeBackInset",              BOOLEAN, REMOVE_BACK_INSET              )
 
 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)
@@ -590,6 +592,18 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro
         }
         break;
       }
+      case Toolkit::DevelTextLabel::Property::REMOVE_FRONT_INSET:
+      {
+        const bool remove = value.Get<bool>();
+        impl.mController->SetRemoveFrontInset(remove);
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::REMOVE_BACK_INSET:
+      {
+        const bool remove = value.Get<bool>();
+        impl.mController->SetRemoveBackInset(remove);
+        break;
+      }
     }
 
     // Request relayout when text update is needed. It's necessary to call it
@@ -864,6 +878,16 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index
         value = impl.mController->GetAnchorClickedColor();
         break;
       }
+      case Toolkit::DevelTextLabel::Property::REMOVE_FRONT_INSET:
+      {
+        value = impl.mController->IsRemoveFrontInset();
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::REMOVE_BACK_INSET:
+      {
+        value = impl.mController->IsRemoveBackInset();
+        break;
+      }
     }
   }
 
@@ -1369,6 +1393,26 @@ bool TextLabel::IsTextFitArrayEnabled() const
   return mController->IsTextFitArrayEnabled();
 }
 
+void TextLabel::SetRemoveFrontInset(bool remove)
+{
+  mController->SetRemoveFrontInset(remove);
+}
+
+bool TextLabel::IsRemoveFrontInset() const
+{
+  return mController->IsRemoveFrontInset();
+}
+
+void TextLabel::SetRemoveBackInset(bool remove)
+{
+  mController->SetRemoveBackInset(remove);
+}
+
+bool TextLabel::IsRemoveBackInset() const
+{
+  return mController->IsRemoveBackInset();
+}
+
 std::string TextLabel::TextLabelAccessible::GetNameRaw() const
 {
   return GetWholeText();
index 7ef28c6..5730cc5 100644 (file)
@@ -198,6 +198,34 @@ public:
    */
   std::string GetLocale();
 
+  /**
+   * @brief Set removing front inset to text label.
+   *
+   * @param[in] remove Whether front inset of text label has to be removed or not.
+   */
+  void SetRemoveFrontInset(const bool remove);
+
+  /**
+   * @brief Whether front inset of text label is removed or not.
+   *
+   * @return True if the front inset of text label is removed.
+   */
+  bool IsRemoveFrontInset() const;
+
+  /**
+   * @brief Set removing back inset to text label.
+   *
+   * @param[in] remove Whether back inset of text label has to be removed or not.
+   */
+  void SetRemoveBackInset(const bool remove);
+
+  /**
+   * @brief Whether back inset of text label is removed or not.
+   *
+   * @return True if the back inset of text label is removed.
+   */
+  bool IsRemoveBackInset() const;
+
 private: // From Control
   /**
    * @copydoc Control::OnInitialize()
index b2c67e1..d17e187 100644 (file)
@@ -304,6 +304,26 @@ void Controller::SetIgnoreSpacesAfterText(bool ignore)
   mImpl->mModel->mIgnoreSpacesAfterText = ignore;
 }
 
+bool Controller::IsRemoveFrontInset() const
+{
+  return mImpl->mModel->mRemoveFrontInset;
+}
+
+void Controller::SetRemoveFrontInset(bool remove)
+{
+  mImpl->mModel->mRemoveFrontInset = remove;
+}
+
+bool Controller::IsRemoveBackInset() const
+{
+  return mImpl->mModel->mRemoveBackInset;
+}
+
+void Controller::SetRemoveBackInset(bool remove)
+{
+  mImpl->mModel->mRemoveBackInset = remove;
+}
+
 void Controller::ChangedLayoutDirection()
 {
   mImpl->mIsLayoutDirectionChanged = true;
index 41910ab..b8ff325 100644 (file)
@@ -1800,6 +1800,30 @@ public: // Queries & retrieves.
   void SetIgnoreSpacesAfterText(bool ignore);
 
   /**
+   * @brief Retrieves removeFrontInset value from model
+   * @return The value of removeFrontInset
+   */
+  bool IsRemoveFrontInset() const;
+
+  /**
+   * @brief Sets removeFrontInset value to model
+   * @param[in] remove The value of removeFrontInset for the text
+   */
+  void SetRemoveFrontInset(bool remove);
+
+  /**
+   * @brief Retrieves removeBackInset value from model
+   * @return The value of removeBackInset
+   */
+  bool IsRemoveBackInset() const;
+
+  /**
+   * @brief Sets removeBackInset value to model
+   * @param[in] remove The value of removeBackInset for the text
+   */
+  void SetRemoveBackInset(bool remove);
+
+  /**
    * @brief Sets SetMatchLayoutDirection value to model
    * @param[in] match The value of matchLayoutDirection for the text
    */
index 57f4d6c..e78a544 100644 (file)
@@ -449,7 +449,16 @@ struct Engine::Impl
           {
             whiteSpaceLengthEndOfLine = 0.f;
           }
-          length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+
+          if(parameters.textModel->mRemoveBackInset)
+          {
+            length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+          }
+          else
+          {
+            length = std::max(length, penX + glyphMetrics.advance);
+          }
+
           penX += (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
         }
       }
@@ -512,7 +521,15 @@ struct Engine::Impl
         {
           whiteSpaceLengthEndOfLine = 0.f;
         }
-        length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+
+        if(parameters.textModel->mRemoveBackInset)
+        {
+          length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+        }
+        else
+        {
+          length = std::max(length, penX + glyphMetrics.advance);
+        }
         penX += (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
       }
     }
@@ -745,7 +762,12 @@ struct Engine::Impl
     // The initial start point is zero. However it needs a correction according the 'x' bearing of the first glyph.
     // i.e. if the bearing of the first glyph is negative it may exceed the boundaries of the text area.
     // It needs to add as well space for the cursor if the text is in edit mode and extra space in case the text is outlined.
-    tmpLineLayout.penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+
+    tmpLineLayout.penX = mCursorWidth + outlineWidth;
+    if(parameters.textModel->mRemoveFrontInset)
+    {
+      tmpLineLayout.penX -= glyphMetrics.xBearing;
+    }
 
     tmpLineLayout.relativeLineSize = lineLayout.relativeLineSize;
 
@@ -842,7 +864,14 @@ struct Engine::Impl
         tmpLineLayout.penX += tmpLineLayout.previousAdvance + tmpLineLayout.whiteSpaceLengthEndOfLine;
         tmpLineLayout.previousAdvance = (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
 
-        tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width);
+        if(parameters.textModel->mRemoveBackInset)
+        {
+          tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width);
+        }
+        else
+        {
+          tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.advance);
+        }
 
         // Clear the white space length at the end of the line.
         tmpLineLayout.whiteSpaceLengthEndOfLine = 0.f;
@@ -1105,7 +1134,12 @@ struct Engine::Impl
     // If it has a negative x bearing, it will exceed the boundaries of the actor,
     // so the penX position needs to be moved to the right.
     const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyph);
-    float            penX  = -glyph.xBearing + mCursorWidth + outlineWidth; //
+    float            penX  = mCursorWidth + outlineWidth; //
+
+    if(layoutParameters.textModel->mRemoveFrontInset)
+    {
+      penX -= glyph.xBearing;
+    }
 
     CalculateGlyphPositionsLTR(layoutParameters.textModel->mVisualModel,
                                layoutParameters.textModel->mLogicalModel,
index 0f93cb3..ae0dd7c 100644 (file)
@@ -358,6 +358,8 @@ Model::Model()
   mAlignmentOffset(0.0f),
   mElideEnabled(false),
   mIgnoreSpacesAfterText(true),
+  mRemoveFrontInset(true),
+  mRemoveBackInset(true),
   mMatchLayoutDirection(DevelText::MatchLayoutDirection::INHERIT),
   mEllipsisPosition(DevelText::EllipsisPosition::END)
 {
index 012c86f..e738784 100644 (file)
@@ -398,6 +398,8 @@ public:
   float                                  mAlignmentOffset;           ///< The alignment offset.
   bool                                   mElideEnabled : 1;          ///< Whether the text's elide is enabled.
   bool                                   mIgnoreSpacesAfterText : 1; ///< Whether ignoring spaces after text or not. Default is true.
+  bool                                   mRemoveFrontInset : 1;      ///< Whether to ignore xBearing of the first glyph. Default is true.
+  bool                                   mRemoveBackInset : 1;       ///< Whether to ignore advance of the last glyph. Default is true.
   DevelText::MatchLayoutDirection        mMatchLayoutDirection;      ///< Whether to match text alignment with layout direction or not.
   DevelText::EllipsisPosition::Type      mEllipsisPosition;          ///< Where is the location the text elide
   Vector2                                mVisualTransformOffset;     ///< The offset of the layout based on the controller due to alignment.