Merge "Adding Character Spacing" into devel/master
authorBowon Ryu <bowon.ryu@samsung.com>
Thu, 27 Jan 2022 01:19:30 +0000 (01:19 +0000)
committerGerrit Code Review <gerrit@review>
Thu, 27 Jan 2022 01:19:30 +0000 (01:19 +0000)
1  2 
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/controls/text-controls/text-field-devel.h
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp

@@@ -140,7 -140,6 +140,7 @@@ static boo
  static uint32_t                                    oldSelectionStart;
  static uint32_t                                    oldSelectionEnd;
  static bool                                        gSelectionClearedCallbackCalled;
 +static bool                                        gSelectionStartedCallbackCalled;
  static bool                                        gAnchorClickedCallBackCalled;
  static bool                                        gAnchorClickedCallBackNotCalled;
  static bool                                        gTextChangedCallBackCalled;
@@@ -166,13 -165,6 +166,13 @@@ struct CallbackFuncto
    bool* mCallbackFlag;
  };
  
 +static void TestSelectionStartedCallback(TextEditor control)
 +{
 +  tet_infoline(" TestSelectionStartedCallback");
 +
 +  gSelectionStartedCallbackCalled = true;
 +}
 +
  static void TestSelectionClearedCallback(TextEditor control)
  {
    tet_infoline(" TestSelectionClearedCallback");
@@@ -5030,72 -5022,6 +5030,72 @@@ int utcDaliTextEditorSelectionClearedSi
    END_TEST;
  }
  
 +int utcDaliTextEditorSelectionStartedSignal(void)
 +{
 +  ToolkitTestApplication application;
 +  tet_infoline(" utcDaliTextEditorSelectionStartedSignal");
 +
 +  TextEditor editor = TextEditor::New();
 +  DALI_TEST_CHECK(editor);
 +
 +  application.GetScene().Add(editor);
 +
 +  // connect to the selection changed signal.
 +  ConnectionTracker* testTracker = new ConnectionTracker();
 +  DevelTextEditor::SelectionStartedSignal(editor).Connect(&TestSelectionStartedCallback);
 +  bool selectionStartedSignal = false;
 +  editor.ConnectSignal(testTracker, "selectionStarted", CallbackFunctor(&selectionStartedSignal));
 +
 +  editor.SetProperty(TextEditor::Property::TEXT, "Hello\nworld\nHello world");
 +  editor.SetProperty(TextEditor::Property::POINT_SIZE, 10.f);
 +  editor.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f));
 +  editor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
 +  editor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
 +
 +  // Avoid a crash when core load gl resources.
 +  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Tap on the text editor
 +  TestGenerateTap(application, 3.0f, 25.0f);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Move to second line of the text & Select some text in the right of the current cursor position
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  DALI_TEST_CHECK(gSelectionStartedCallbackCalled);
 +
 +  // remove selection
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::UP, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  gSelectionStartedCallbackCalled = false;
 +
 +  DevelTextEditor::SelectText(editor, 1, 3);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  DALI_TEST_CHECK(gSelectionStartedCallbackCalled);
 +
 +  END_TEST;
 +}
 +
  int utcDaliTextEditorSelectionWithSecondaryCursor(void)
  {
    ToolkitTestApplication application;
@@@ -5719,6 -5645,30 +5719,30 @@@ int UtcDaliToolkitTextEditorUnderlineTy
    DALI_TEST_EQUALS(DaliTestCheckMaps(underlineMapGet1, underlineMapSet1), true, TEST_LOCATION);
  
    application.GetScene().Add(textEditor1);
+   application.SendNotification();
+   application.Render();
+   END_TEST;
+ }
+ int UtcDaliTextEditorCharacterSpacing(void)
+ {
+   ToolkitTestApplication application;
+   tet_infoline(" UtcDaliTextEditorCharacterSpacing ");
+   TextEditor textEditor = TextEditor::New();
+   textEditor.SetProperty(Actor::Property::SIZE, Vector2(150.0f, 300.f));
+   application.GetScene().Add(textEditor);
+   application.SendNotification();
+   application.Render();
+   textEditor.SetProperty(TextEditor::Property::TEXT, "Hi Experiment");
+   textEditor.SetProperty(DevelTextEditor::Property::CHARACTER_SPACING, 10.f);
+   DALI_TEST_EQUALS(textEditor.GetProperty<float>(DevelTextEditor::Property::CHARACTER_SPACING), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
    application.SendNotification();
    application.Render();
  
@@@ -131,7 -131,6 +131,7 @@@ static boo
  static uint32_t                                   oldSelectionStart;
  static uint32_t                                   oldSelectionEnd;
  static bool                                       gSelectionClearedCallbackCalled;
 +static bool                                       gSelectionStartedCallbackCalled;
  static bool                                       gAnchorClickedCallBackCalled;
  static bool                                       gAnchorClickedCallBackNotCalled;
  static bool                                       gTextChangedCallBackCalled;
@@@ -230,13 -229,6 +230,13 @@@ static void TestSelectionClearedCallbac
    gSelectionClearedCallbackCalled = true;
  }
  
 +static void TestSelectionStartedCallback(TextField control)
 +{
 +  tet_infoline(" TestSelectionStartedCallback");
 +
 +  gSelectionStartedCallbackCalled = true;
 +}
 +
  static void TestSelectionChangedCallback(TextField control, uint32_t oldStart, uint32_t oldEnd)
  {
    tet_infoline(" TestSelectionChangedCallback");
@@@ -4790,72 -4782,6 +4790,72 @@@ int utcDaliTextFieldSelectionClearedSig
    END_TEST;
  }
  
 +int utcDaliTextFieldSelectionStartedSignal(void)
 +{
 +  ToolkitTestApplication application;
 +  tet_infoline(" utcDaliTextFieldSelectionStartedSignal");
 +
 +  TextField field = TextField::New();
 +  DALI_TEST_CHECK(field);
 +
 +  application.GetScene().Add(field);
 +
 +  // connect to the selection changed signal.
 +  ConnectionTracker* testTracker = new ConnectionTracker();
 +  DevelTextField::SelectionStartedSignal(field).Connect(&TestSelectionStartedCallback);
 +  bool selectionStartedSignal = false;
 +  field.ConnectSignal(testTracker, "selectionStarted", CallbackFunctor(&selectionStartedSignal));
 +
 +  field.SetProperty(TextField::Property::TEXT, "Hello\nworld\nHello world");
 +  field.SetProperty(TextField::Property::POINT_SIZE, 10.f);
 +  field.SetProperty(Actor::Property::SIZE, Vector2(100.f, 50.f));
 +  field.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
 +  field.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
 +
 +  // Avoid a crash when core load gl resources.
 +  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Tap on the text field
 +  TestGenerateTap(application, 3.0f, 25.0f);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Move to second line of the text & Select some text in the right of the current cursor position
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  DALI_TEST_CHECK(gSelectionStartedCallbackCalled);
 +
 +  // remove selection
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::UP, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  gSelectionStartedCallbackCalled = false;
 +
 +  DevelTextField::SelectText(field, 1, 3);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  DALI_TEST_CHECK(gSelectionStartedCallbackCalled);
 +
 +  END_TEST;
 +}
 +
  int utcDaliTextFieldSelectionChangedSignal(void)
  {
    ToolkitTestApplication application;
@@@ -5216,6 -5142,30 +5216,30 @@@ int UtcDaliToolkitTextFieldUnderlineTyp
    DALI_TEST_EQUALS(DaliTestCheckMaps(underlineMapGet3, underlineMapSet3), true, TEST_LOCATION);
  
    application.GetScene().Add(field3);
+   application.SendNotification();
+   application.Render();
+   END_TEST;
+ }
+ int UtcDaliTextFieldCharacterSpacing(void)
+ {
+   ToolkitTestApplication application;
+   tet_infoline(" UtcDaliTextFieldCharacterSpacing ");
+   TextField textField = TextField::New();
+   textField.SetProperty(Actor::Property::SIZE, Vector2(150.0f, 300.f));
+   application.GetScene().Add(textField);
+   application.SendNotification();
+   application.Render();
+   textField.SetProperty(TextField::Property::TEXT, "Hi Experiment");
+   textField.SetProperty(DevelTextField::Property::CHARACTER_SPACING, 10.f);
+   DALI_TEST_EQUALS(textField.GetProperty<float>(DevelTextField::Property::CHARACTER_SPACING), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
    application.SendNotification();
    application.Render();
  
@@@ -294,6 -294,15 +294,15 @@@ enum Typ
     * @details Name "inputStrikethrough", type Property::MAP.
     */
    INPUT_STRIKETHROUGH,
+   /**
+   * @brief The spaces between characters in Pixels.
+   * @details Name "characterSpacing", type Property::FLOAT.
+   * @note
+   *   A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+   *   The default value is 0.f which does nothing.
+   */
+   CHARACTER_SPACING,
  };
  
  } // namespace Property
@@@ -434,23 -443,6 +443,23 @@@ using SelectionClearedSignalType = Sign
  DALI_TOOLKIT_API SelectionClearedSignalType& SelectionClearedSignal(TextEditor textEditor);
  
  /**
 + * @brief selection start signal type.
 + */
 +using SelectionStartedSignalType = Signal<void(TextEditor)>;
 +
 +/**
 + * @brief This signal is emitted when the selection start.
 + *
 + * A callback of the following type may be connected:
 + * @code
 + *   void YourCallbackName( TextEditor textEditor);
 + * @endcode
 + * @param[in] textEditor The instance of TextEditor.
 + * @return The signal to connect to
 + */
 +DALI_TOOLKIT_API SelectionStartedSignalType& SelectionStartedSignal(TextEditor textEditor);
 +
 +/**
   * @brief Select the whole text of TextEditor.
   *
   * @param[in] textEditor The instance of TextEditor.
@@@ -233,6 -233,15 +233,15 @@@ enu
     * @details Name "inputStrikethrough", type Property::MAP.
     */
    INPUT_STRIKETHROUGH,
+   /**
+   * @brief The spaces between characters in Pixels.
+   * @details Name "characterSpacing", type Property::FLOAT.
+   * @note
+   *   A positive value will make the characters far apart (expanded) and a negative value will bring them closer (condensed).
+   *   The default value is 0.f which does nothing.
+   */
+   CHARACTER_SPACING,
  };
  
  } // namespace Property
@@@ -356,23 -365,6 +365,23 @@@ using SelectionClearedSignalType = Sign
  DALI_TOOLKIT_API SelectionClearedSignalType& SelectionClearedSignal(TextField textField);
  
  /**
 + * @brief selection start signal type.
 + */
 +using SelectionStartedSignalType = Signal<void(TextField)>;
 +
 +/**
 + * @brief This signal is emitted when the selection start.
 + *
 + * A callback of the following type may be connected:
 + * @code
 + *   void YourCallbackName( TextField textField);
 + * @endcode
 + * @param[in] textField The instance of TextField.
 + * @return The signal to connect to
 + */
 +DALI_TOOLKIT_API SelectionStartedSignalType& SelectionStartedSignal(TextField textField);
 +
 +/**
   * @brief Get the rendered size of a specific text range.
   * if the requested text is at multilines, multiple sizes will be returned for each text located in a separate line.
   * if a line contains characters with different directions, multiple sizes will be returned for each block of contiguous characters with the same direction.
@@@ -157,6 -157,7 +157,7 @@@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolki
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "minLineSize",                          FLOAT,     MIN_LINE_SIZE                       )
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "strikethrough",                        MAP,       STRIKETHROUGH                       )
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputStrikethrough",                   MAP,       INPUT_STRIKETHROUGH                 )
+ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "characterSpacing",                     FLOAT,     CHARACTER_SPACING                   )
  
  DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged",           SIGNAL_TEXT_CHANGED           )
  DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged",     SIGNAL_INPUT_STYLE_CHANGED    )
@@@ -166,7 -167,6 +167,7 @@@ DALI_SIGNAL_REGISTRATION(Toolkit, TextE
  DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "cursorPositionChanged", SIGNAL_CURSOR_POSITION_CHANGED)
  DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionChanged",      SIGNAL_SELECTION_CHANGED      )
  DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionCleared",      SIGNAL_SELECTION_CLEARED      )
 +DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionStarted",      SIGNAL_SELECTION_STARTED      )
  
  DALI_TYPE_REGISTRATION_END()
  // clang-format on
@@@ -405,11 -405,6 +406,11 @@@ DevelTextEditor::SelectionClearedSignal
    return mSelectionClearedSignal;
  }
  
 +DevelTextEditor::SelectionStartedSignalType& TextEditor::SelectionStartedSignal()
 +{
 +  return mSelectionStartedSignal;
 +}
 +
  Text::ControllerPtr TextEditor::GetTextController()
  {
    return mController;
@@@ -478,14 -473,6 +479,14 @@@ bool TextEditor::DoConnectSignal(BaseOb
        editorImpl.SelectionClearedSignal().Connect(tracker, functor);
      }
    }
 +  else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_STARTED))
 +  {
 +    if(editor)
 +    {
 +      Internal::TextEditor& editorImpl(GetImpl(editor));
 +      editorImpl.SelectionStartedSignal().Connect(tracker, functor);
 +    }
 +  }
    else
    {
      // signalName does not match any signal
@@@ -732,11 -719,6 +733,11 @@@ void TextEditor::OnRelayout(const Vecto
      EmitCursorPositionChangedSignal();
    }
  
 +  if(mSelectionStarted)
 +  {
 +    EmitSelectionStartedSignal();
 +  }
 +
    if(mSelectionChanged)
    {
      EmitSelectionChangedSignal();
@@@ -994,13 -976,6 +995,13 @@@ void TextEditor::EmitSelectionClearedSi
    mSelectionCleared = false;
  }
  
 +void TextEditor::EmitSelectionStartedSignal()
 +{
 +  Dali::Toolkit::TextEditor handle(GetOwner());
 +  mSelectionStartedSignal.Emit(handle);
 +  mSelectionStarted = false;
 +}
 +
  void TextEditor::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
  {
    if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
      {
        mSelectionCleared = true;
      }
 +    else
 +    {
 +      if(oldStart == oldEnd)
 +      {
 +        mSelectionStarted = true;
 +      }
 +    }
  
      mSelectionChanged  = true;
      mOldSelectionStart = oldStart;
@@@ -1315,8 -1283,7 +1316,8 @@@ TextEditor::TextEditor(
    mSelectionCleared(false),
    mOldPosition(0u),
    mOldSelectionStart(0u),
 -  mOldSelectionEnd(0u)
 +  mOldSelectionEnd(0u),
 +  mSelectionStarted(false)
  {
  }
  
@@@ -144,6 -144,7 +144,7 @@@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolki
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "ellipsisPosition",                 INTEGER,   ELLIPSIS_POSITION                   )
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "strikethrough",                    MAP,       STRIKETHROUGH                       )
  DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "inputStrikethrough",               MAP,       INPUT_STRIKETHROUGH                 )
+ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "characterSpacing",                 FLOAT,     CHARACTER_SPACING                   )
  
  DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "textChanged",           SIGNAL_TEXT_CHANGED           )
  DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "maxLengthReached",      SIGNAL_MAX_LENGTH_REACHED     )
@@@ -153,7 -154,6 +154,7 @@@ DALI_SIGNAL_REGISTRATION(Toolkit, TextF
  DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "cursorPositionChanged", SIGNAL_CURSOR_POSITION_CHANGED)
  DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "selectionChanged",      SIGNAL_SELECTION_CHANGED      )
  DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "selectionCleared",      SIGNAL_SELECTION_CLEARED      )
 +DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "selectionStarted",      SIGNAL_SELECTION_STARTED      )
  
  DALI_TYPE_REGISTRATION_END()
  // clang-format on
@@@ -418,14 -418,6 +419,14 @@@ bool TextField::DoConnectSignal(BaseObj
        fieldImpl.SelectionClearedSignal().Connect(tracker, functor);
      }
    }
 +  else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_STARTED))
 +  {
 +    if(field)
 +    {
 +      Internal::TextField& fieldImpl(GetImpl(field));
 +      fieldImpl.SelectionStartedSignal().Connect(tracker, functor);
 +    }
 +  }
    else
    {
      // signalName does not match any signal
@@@ -475,11 -467,6 +476,11 @@@ DevelTextField::SelectionClearedSignalT
    return mSelectionClearedSignal;
  }
  
 +DevelTextField::SelectionStartedSignalType& TextField::SelectionStartedSignal()
 +{
 +  return mSelectionStartedSignal;
 +}
 +
  void TextField::OnAccessibilityStatusChanged()
  {
    CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
@@@ -690,11 -677,6 +691,11 @@@ void TextField::OnRelayout(const Vector
      EmitCursorPositionChangedSignal();
    }
  
 +  if(mSelectionStarted)
 +  {
 +    EmitSelectionStartedSignal();
 +  }
 +
    if(mSelectionChanged)
    {
      EmitSelectionChangedSignal();
@@@ -970,13 -952,6 +971,13 @@@ void TextField::EmitSelectionClearedSig
    mSelectionCleared = false;
  }
  
 +void TextField::EmitSelectionStartedSignal()
 +{
 +  Dali::Toolkit::TextField handle(GetOwner());
 +  mSelectionStartedSignal.Emit(handle);
 +  mSelectionStarted = false;
 +}
 +
  void TextField::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
  {
    if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
      {
        mSelectionCleared = true;
      }
 +    else
 +    {
 +      if(oldStart == oldEnd)
 +      {
 +        mSelectionStarted = true;
 +      }
 +    }
  
      mSelectionChanged  = true;
      mOldSelectionStart = oldStart;
@@@ -1150,8 -1118,7 +1151,8 @@@ TextField::TextField(
    mSelectionCleared(false),
    mOldPosition(0u),
    mOldSelectionStart(0u),
 -  mOldSelectionEnd(0u)
 +  mOldSelectionEnd(0u),
 +  mSelectionStarted(false)
  {
  }