Merge "DALi Version 2.0.41" into devel/master
authorDavid Steele <david.steele@samsung.com>
Fri, 27 Aug 2021 11:43:07 +0000 (11:43 +0000)
committerGerrit Code Review <gerrit@review>
Fri, 27 Aug 2021 11:43:07 +0000 (11:43 +0000)
16 files changed:
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.cpp
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/controls/text-controls/text-field-devel.cpp
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-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/text/text-controller-impl-event-handler.cpp
dali-toolkit/internal/text/text-controller-text-updater.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h

index 0d0b8bc..02dff2e 100644 (file)
@@ -136,6 +136,7 @@ const std::string DEFAULT_DEVICE_NAME("hwKeyboard");
 static bool gSelectionChangedCallbackCalled;
 static uint32_t oldSelectionStart;
 static uint32_t oldSelectionEnd;
+static bool gSelectionClearedCallbackCalled;
 static bool gAnchorClickedCallBackCalled;
 static bool gAnchorClickedCallBackNotCalled;
 static bool gTextChangedCallBackCalled;
@@ -161,6 +162,13 @@ struct CallbackFunctor
   bool* mCallbackFlag;
 };
 
+static void TestSelectionClearedCallback(TextEditor control)
+{
+  tet_infoline(" TestSelectionClearedCallback");
+
+  gSelectionClearedCallbackCalled = true;
+}
+
 static void TestSelectionChangedCallback(TextEditor control, uint32_t oldStart, uint32_t oldEnd)
 {
   tet_infoline(" TestSelectionChangedCallback");
@@ -4447,6 +4455,140 @@ int utcDaliTextEditorCursorPositionChangedSignal(void)
   END_TEST;
 }
 
+int utcDaliTextEditorSelectionClearedSignal(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorSelectionClearedSignal");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  application.GetScene().Add( editor );
+
+  // connect to the selection changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  DevelTextEditor::SelectionClearedSignal(editor).Connect(&TestSelectionClearedCallback);
+  bool selectionClearedSignal = false;
+  editor.ConnectSignal( testTracker, "selectionCleared",   CallbackFunctor(&selectionClearedSignal) );
+
+  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 ) );
+
+  // 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();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  // 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();
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Move to second line of the text & select.
+  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 ) );
+
+  //remove selection
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move to second line of the text & select.
+  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 ) );
+
+  // replace C with selected text
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, 0, 0, Integration::KeyEvent::DOWN, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DevelTextEditor::SelectText( editor ,1, 3 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  editor.SetProperty( DevelTextEditor::Property::PRIMARY_CURSOR_POSITION, 3);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  DevelTextEditor::SelectText( editor ,1, 3 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // select none
+  DevelTextEditor::SelectNone(editor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  END_TEST;
+}
+
 int utcDaliTextEditorSelectionChangedSignal(void)
 {
   ToolkitTestApplication application;
index 7e9c6eb..e8bf4b6 100644 (file)
@@ -127,6 +127,7 @@ const std::string DEFAULT_DEVICE_NAME("hwKeyboard");
 static bool gSelectionChangedCallbackCalled;
 static uint32_t oldSelectionStart;
 static uint32_t oldSelectionEnd;
+static bool gSelectionClearedCallbackCalled;
 static bool gAnchorClickedCallBackCalled;
 static bool gAnchorClickedCallBackNotCalled;
 static bool gTextChangedCallBackCalled;
@@ -218,6 +219,13 @@ struct CallbackFunctor
   bool* mCallbackFlag;
 };
 
+static void TestSelectionClearedCallback(TextField control)
+{
+  tet_infoline(" TestSelectionClearedCallback");
+
+  gSelectionClearedCallbackCalled = true;
+}
+
 static void TestSelectionChangedCallback(TextField control, uint32_t oldStart, uint32_t oldEnd)
 {
   tet_infoline(" TestSelectionChangedCallback");
@@ -4383,6 +4391,140 @@ int utcDaliTextFieldCursorPositionChangedSignal(void)
   END_TEST;
 }
 
+int utcDaliTextFieldSelectionClearedSignal(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldSelectionClearedSignal");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  application.GetScene().Add( field );
+
+  // connect to the selection changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  DevelTextField::SelectionClearedSignal(field).Connect(&TestSelectionClearedCallback);
+  bool selectionClearedSignal = false;
+  field.ConnectSignal( testTracker, "selectionCleared",   CallbackFunctor(&selectionClearedSignal) );
+
+  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 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 ) );
+
+  // 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();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  // 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();
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Move to second line of the text & select.
+  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 ) );
+
+  //remove selection
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move to second line of the text & select.
+  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 ) );
+
+  // replace D with selected text
+  application.ProcessEvent( GenerateKey( "D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DevelTextField::SelectText( field ,1, 3 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( DevelTextField::Property::PRIMARY_CURSOR_POSITION, 3);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  gSelectionClearedCallbackCalled = false;
+
+  DevelTextField::SelectText( field ,1, 3 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // select none
+  DevelTextField::SelectNone(field);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSelectionClearedCallbackCalled);
+
+  END_TEST;
+}
+
 int utcDaliTextFieldSelectionChangedSignal(void)
 {
   ToolkitTestApplication application;
index 74a57e6..f3f073b 100644 (file)
@@ -55,6 +55,11 @@ SelectionChangedSignalType& SelectionChangedSignal(TextEditor textEditor)
   return GetImpl(textEditor).SelectionChangedSignal();
 }
 
+SelectionClearedSignalType& SelectionClearedSignal(TextEditor textEditor)
+{
+  return GetImpl(textEditor).SelectionClearedSignal();
+}
+
 void SelectWholeText(TextEditor textEditor)
 {
   GetImpl(textEditor).SelectWholeText();
index 345368d..177be64 100644 (file)
@@ -397,6 +397,23 @@ using SelectionChangedSignalType = Signal<void(TextEditor, uint32_t, uint32_t)>;
 DALI_TOOLKIT_API SelectionChangedSignalType& SelectionChangedSignal(TextEditor textEditor);
 
 /**
+ * @brief selection cleared signal type.
+ */
+using SelectionClearedSignalType = Signal<void(TextEditor)>;
+
+/**
+ * @brief This signal is emitted when the selection has been cleared.
+ *
+ * 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 SelectionClearedSignalType& SelectionClearedSignal(TextEditor textEditor);
+
+/**
  * @brief Select the whole text of TextEditor.
  *
  * @param[in] textEditor The instance of TextEditor.
index e9a609f..e5abdfa 100644 (file)
@@ -50,6 +50,11 @@ SelectionChangedSignalType& SelectionChangedSignal(TextField textField)
   return GetImpl(textField).SelectionChangedSignal();
 }
 
+SelectionClearedSignalType& SelectionClearedSignal(TextField textField)
+{
+  return GetImpl(textField).SelectionClearedSignal();
+}
+
 void SelectWholeText(TextField textField)
 {
   GetImpl(textField).SelectWholeText();
index 4dff21d..10d79e8 100644 (file)
@@ -319,6 +319,23 @@ using SelectionChangedSignalType = Signal<void(TextField, uint32_t, uint32_t)>;
 DALI_TOOLKIT_API SelectionChangedSignalType& SelectionChangedSignal(TextField textField);
 
 /**
+ * @brief selection cleared signal type.
+ */
+using SelectionClearedSignalType = Signal<void(TextField)>;
+
+/**
+ * @brief This signal is emitted when the selection has been cleared.
+ *
+ * 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 SelectionClearedSignalType& SelectionClearedSignal(TextField textField);
+
+/**
  * @brief Select the whole text of TextField.
  *
  * @param[in] textField The instance of TextField.
index 7a3b4ba..47e4c0a 100644 (file)
@@ -160,6 +160,7 @@ DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "anchorClicked",         SIGNAL_AN
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputFiltered",         SIGNAL_INPUT_FILTERED         )
 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_TYPE_REGISTRATION_END()
 // clang-format on
@@ -1358,6 +1359,11 @@ DevelTextEditor::SelectionChangedSignalType& TextEditor::SelectionChangedSignal(
   return mSelectionChangedSignal;
 }
 
+DevelTextEditor::SelectionClearedSignalType& TextEditor::SelectionClearedSignal()
+{
+  return mSelectionClearedSignal;
+}
+
 Text::ControllerPtr TextEditor::GetTextController()
 {
   return mController;
@@ -1418,6 +1424,14 @@ bool TextEditor::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface*
       editorImpl.SelectionChangedSignal().Connect(tracker, functor);
     }
   }
+  else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_CLEARED))
+  {
+    if(editor)
+    {
+      Internal::TextEditor& editorImpl(GetImpl(editor));
+      editorImpl.SelectionClearedSignal().Connect(tracker, functor);
+    }
+  }
   else
   {
     // signalName does not match any signal
@@ -1660,6 +1674,11 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
     EmitSelectionChangedSignal();
   }
 
+  if(mSelectionCleared)
+  {
+    EmitSelectionClearedSignal();
+  }
+
   // The text-editor emits signals when the input style changes. These changes of style are
   // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
   // can't be emitted during the size negotiation as the callbacks may update the UI.
@@ -2039,10 +2058,22 @@ void TextEditor::EmitSelectionChangedSignal()
   mSelectionChanged = false;
 }
 
+void TextEditor::EmitSelectionClearedSignal()
+{
+  Dali::Toolkit::TextEditor handle(GetOwner());
+  mSelectionClearedSignal.Emit(handle);
+  mSelectionCleared = false;
+}
+
 void TextEditor::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
 {
   if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
   {
+    if(newStart == newEnd)
+    {
+      mSelectionCleared = true;
+    }
+
     mSelectionChanged  = true;
     mOldSelectionStart = oldStart;
     mOldSelectionEnd   = oldEnd;
@@ -2336,7 +2367,8 @@ TextEditor::TextEditor()
   mScrollStarted(false),
   mTextChanged(false),
   mCursorPositionChanged(false),
-  mSelectionChanged(false)
+  mSelectionChanged(false),
+  mSelectionCleared(false)
 {
 }
 
index aff671a..bc28781 100644 (file)
@@ -108,6 +108,11 @@ public:
   DevelTextEditor::SelectionChangedSignalType& SelectionChangedSignal();
 
   /**
+   * @copydoc Dali::Toollkit::TextEditor::SelectionClearedSignal()
+   */
+  DevelTextEditor::SelectionClearedSignalType& SelectionClearedSignal();
+
+  /**
    * Connects a callback function with the object's signals.
    * @param[in] object The object providing the signal.
    * @param[in] tracker Used to disconnect the signal.
@@ -413,6 +418,11 @@ private: // Implementation
   void EmitSelectionChangedSignal();
 
   /**
+   * @brief Emits SelectionCleared signal.
+   */
+  void EmitSelectionClearedSignal();
+
+  /**
    * @brief set RenderActor's position with new scrollPosition
    *
    * Apply updated scroll position or start scroll animation if VerticalScrollAnimation is enabled
@@ -473,6 +483,7 @@ private: // Data
   Toolkit::DevelTextEditor::InputFilteredSignalType         mInputFilteredSignal;
   Toolkit::DevelTextEditor::CursorPositionChangedSignalType mCursorPositionChangedSignal;
   Toolkit::DevelTextEditor::SelectionChangedSignalType      mSelectionChangedSignal;
+  Toolkit::DevelTextEditor::SelectionClearedSignalType      mSelectionClearedSignal;
 
   InputMethodContext            mInputMethodContext;
   Text::ControllerPtr           mController;
@@ -502,6 +513,7 @@ private: // Data
   bool  mTextChanged : 1;           ///< If true, emits TextChangedSignal in next OnRelayout().
   bool  mCursorPositionChanged : 1; ///< If true, emits CursorPositionChangedSignal at the end of OnRelayout().
   bool  mSelectionChanged : 1;      ///< If true, emits SelectionChangedSignal at the end of OnRelayout().
+  bool  mSelectionCleared : 1;      ///< If true, emits SelectionClearedSignal at the end of OnRelayout().
 
   //args for cursor PositionChanged event
   unsigned int mOldPosition;
index c6fd205..6e08da1 100644 (file)
@@ -147,6 +147,7 @@ DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "anchorClicked",         SIGNAL_ANC
 DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "inputFiltered",         SIGNAL_INPUT_FILTERED         )
 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_TYPE_REGISTRATION_END()
 // clang-format on
@@ -1301,6 +1302,14 @@ bool TextField::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface*
       fieldImpl.SelectionChangedSignal().Connect(tracker, functor);
     }
   }
+  else if(0 == strcmp(signalName.c_str(), SIGNAL_SELECTION_CLEARED))
+  {
+    if(field)
+    {
+      Internal::TextField& fieldImpl(GetImpl(field));
+      fieldImpl.SelectionClearedSignal().Connect(tracker, functor);
+    }
+  }
   else
   {
     // signalName does not match any signal
@@ -1345,6 +1354,11 @@ DevelTextField::SelectionChangedSignalType& TextField::SelectionChangedSignal()
   return mSelectionChangedSignal;
 }
 
+DevelTextField::SelectionClearedSignalType& TextField::SelectionClearedSignal()
+{
+  return mSelectionClearedSignal;
+}
+
 void TextField::OnInitialize()
 {
   Actor self = Self();
@@ -1551,6 +1565,11 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
     EmitSelectionChangedSignal();
   }
 
+  if(mSelectionCleared)
+  {
+    EmitSelectionClearedSignal();
+  }
+
   // The text-field emits signals when the input style changes. These changes of style are
   // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
   // can't be emitted during the size negotiation as the callbacks may update the UI.
@@ -1947,10 +1966,22 @@ void TextField::EmitSelectionChangedSignal()
   mSelectionChanged = false;
 }
 
+void TextField::EmitSelectionClearedSignal()
+{
+  Dali::Toolkit::TextField handle(GetOwner());
+  mSelectionClearedSignal.Emit(handle);
+  mSelectionCleared = false;
+}
+
 void TextField::SelectionChanged(uint32_t oldStart, uint32_t oldEnd, uint32_t newStart, uint32_t newEnd)
 {
   if(((oldStart != newStart) || (oldEnd != newEnd)) && !mSelectionChanged)
   {
+    if(newStart == newEnd)
+    {
+      mSelectionCleared = true;
+    }
+
     mSelectionChanged  = true;
     mOldSelectionStart = oldStart;
     mOldSelectionEnd   = oldEnd;
@@ -2103,7 +2134,8 @@ TextField::TextField()
   mHasBeenStaged(false),
   mTextChanged(false),
   mCursorPositionChanged(false),
-  mSelectionChanged(false)
+  mSelectionChanged(false),
+  mSelectionCleared(false)
 {
 }
 
index 0b24ff0..0472aa8 100644 (file)
@@ -131,6 +131,11 @@ public:
    */
   DevelTextField::SelectionChangedSignalType& SelectionChangedSignal();
 
+  /**
+   * @copydoc TextField::SelectionClearedSignal()
+   */
+  DevelTextField::SelectionClearedSignalType& SelectionClearedSignal();
+
 private: // From Control
   /**
    * @copydoc Control::OnInitialize()
@@ -383,6 +388,11 @@ private: // Implementation
   void EmitSelectionChangedSignal();
 
   /**
+   * @brief Emits SelectionCleared signal.
+   */
+  void EmitSelectionClearedSignal();
+
+  /**
    * @brief Callback function for when the layout is changed.
    * @param[in] actor The actor whose layoutDirection is changed.
    * @param[in] type  The layoutDirection.
@@ -428,6 +438,7 @@ private: // Data
   Toolkit::DevelTextField::InputFilteredSignalType         mInputFilteredSignal;
   Toolkit::DevelTextField::CursorPositionChangedSignalType mCursorPositionChangedSignal;
   Toolkit::DevelTextField::SelectionChangedSignalType      mSelectionChangedSignal;
+  Toolkit::DevelTextField::SelectionClearedSignalType      mSelectionClearedSignal;
 
   InputMethodContext       mInputMethodContext;
   Text::ControllerPtr      mController;
@@ -449,6 +460,7 @@ private: // Data
   bool  mTextChanged : 1;           ///< If true, emits TextChangedSignal in next OnRelayout().
   bool  mCursorPositionChanged : 1; ///< If true, emits CursorPositionChangedSignal at the end of OnRelayout().
   bool  mSelectionChanged : 1;      ///< If true, emits SelectionChangedSignal at the end of OnRelayout().
+  bool  mSelectionCleared : 1;      ///< If true, emits SelectionClearedSignal at the end of OnRelayout().
 
   //args for cursor position changed event
   unsigned int mOldPosition;
index e24e8aa..e298a5a 100644 (file)
@@ -286,6 +286,8 @@ void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const
   ModelPtr&        model           = impl.mModel;
   LogicalModelPtr& logicalModel    = model->mLogicalModel;
   VisualModelPtr&  visualModel     = model->mVisualModel;
+  uint32_t         oldSelStart     = eventData.mLeftSelectionPosition;
+  uint32_t         oldSelEnd       = eventData.mRightSelectionPosition;
 
   CharacterIndex& primaryCursorPosition         = eventData.mPrimaryCursorPosition;
   CharacterIndex  previousPrimaryCursorPosition = primaryCursorPosition;
@@ -397,6 +399,11 @@ void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const
     // Update selection position after moving the cursor
     eventData.mLeftSelectionPosition  = primaryCursorPosition;
     eventData.mRightSelectionPosition = primaryCursorPosition;
+
+    if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
+    {
+      impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+    }
   }
 
   if(isShiftModifier && impl.IsShowingRealText() && eventData.mShiftSelectionFlag)
@@ -410,14 +417,11 @@ void ControllerImplEventHandler::OnCursorKeyEvent(Controller::Impl& impl, const
       int cursorPositionDelta = primaryCursorPosition - previousPrimaryCursorPosition;
       if(cursorPositionDelta > 0 || eventData.mRightSelectionPosition > 0u) // Check the boundary
       {
-        uint32_t oldStart = eventData.mLeftSelectionPosition;
-        uint32_t oldEnd   = eventData.mRightSelectionPosition;
-
         eventData.mRightSelectionPosition += cursorPositionDelta;
 
         if(impl.mSelectableControlInterface != nullptr)
         {
-          impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
+          impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mLeftSelectionPosition, eventData.mRightSelectionPosition);
         }
       }
       selecting = true;
@@ -477,8 +481,10 @@ void ControllerImplEventHandler::OnTapEvent(Controller::Impl& impl, const Event&
       if(impl.IsShowingRealText())
       {
         // Convert from control's coords to text's coords.
-        const float xPosition = event.p2.mFloat - model->mScrollPosition.x;
-        const float yPosition = event.p3.mFloat - model->mScrollPosition.y;
+        const float xPosition   = event.p2.mFloat - model->mScrollPosition.x;
+        const float yPosition   = event.p3.mFloat - model->mScrollPosition.y;
+        uint32_t    oldSelStart = eventData.mLeftSelectionPosition;
+        uint32_t    oldSelEnd   = eventData.mRightSelectionPosition;
 
         // Keep the tap 'x' position. Used to move the cursor.
         eventData.mCursorHookPositionX = xPosition;
@@ -493,6 +499,11 @@ void ControllerImplEventHandler::OnTapEvent(Controller::Impl& impl, const Event&
                                                                        CharacterHitTest::TAP,
                                                                        matchedCharacter);
 
+        if(impl.mSelectableControlInterface != nullptr && eventData.mDecorator->IsHighlightVisible())
+        {
+          impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, eventData.mPrimaryCursorPosition, eventData.mPrimaryCursorPosition);
+        }
+
         // When the cursor position is changing, delay cursor blinking
         eventData.mDecorator->DelayCursorBlink();
       }
@@ -708,12 +719,11 @@ void ControllerImplEventHandler::OnSelectNoneEvent(Controller::Impl& impl)
     EventData& eventData = *impl.mEventData;
     if(eventData.mSelectionEnabled && eventData.mState == EventData::SELECTING)
     {
-      eventData.mPrimaryCursorPosition = 0u;
       uint32_t oldStart                = eventData.mLeftSelectionPosition;
       uint32_t oldEnd                  = eventData.mRightSelectionPosition;
 
       eventData.mLeftSelectionPosition = eventData.mRightSelectionPosition = eventData.mPrimaryCursorPosition;
-      impl.ChangeState(EventData::INACTIVE);
+      impl.ChangeState(EventData::EDITING);
       eventData.mUpdateCursorPosition      = true;
       eventData.mUpdateInputStyle          = true;
       eventData.mScrollAfterUpdatePosition = true;
index c200c38..75ea73c 100644 (file)
@@ -607,6 +607,9 @@ bool Controller::TextUpdater::RemoveSelectedText(Controller& controller)
   if(EventData::SELECTING == impl.mEventData->mState)
   {
     std::string removedString;
+    uint32_t    oldSelStart = impl.mEventData->mLeftSelectionPosition;
+    uint32_t    oldSelEnd   = impl.mEventData->mRightSelectionPosition;
+
     impl.RetrieveSelection(removedString, true);
 
     if(!removedString.empty())
@@ -623,6 +626,11 @@ bool Controller::TextUpdater::RemoveSelectedText(Controller& controller)
 
         RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
       }
+
+      if(impl.mSelectableControlInterface != nullptr)
+      {
+        impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, impl.mEventData->mPrimaryCursorPosition, impl.mEventData->mPrimaryCursorPosition);
+      }
     }
   }
 
index 2f29ac0..75fa62e 100644 (file)
@@ -524,11 +524,11 @@ uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endF
 
 VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
 {
-  // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
+  // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::steady_clock supported
   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
   // is casted to use the default duration.
   mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
-  auto current        = std::chrono::system_clock::now();
+  auto current        = std::chrono::steady_clock::now();
   if(renderNow)
   {
     mNextFrameStartTime = current;
index c14cc10..3c0b8e3 100644 (file)
@@ -47,7 +47,7 @@ class VectorAnimationTask : public RefObject
 public:
   using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
 
-  using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
+  using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;
 
   /**
    * Flags for re-sending data to the vector animation thread
index a5b1166..97634f6 100644 (file)
@@ -216,7 +216,7 @@ void VectorAnimationThread::Rasterize()
   {
     VectorAnimationTaskPtr nextTask = *it;
 
-    auto currentTime   = std::chrono::system_clock::now();
+    auto currentTime   = std::chrono::steady_clock::now();
     auto nextFrameTime = nextTask->GetNextFrameTime();
 
 #if defined(DEBUG_ENABLED)
@@ -300,7 +300,7 @@ VectorAnimationThread::SleepThread::~SleepThread()
   Join();
 }
 
-void VectorAnimationThread::SleepThread::SleepUntil(std::chrono::time_point<std::chrono::system_clock> timeToSleepUntil)
+void VectorAnimationThread::SleepThread::SleepUntil(std::chrono::time_point<std::chrono::steady_clock> timeToSleepUntil)
 {
   ConditionalWait::ScopedLock lock(mConditionalWait);
   mSleepTimePoint = timeToSleepUntil;
@@ -316,7 +316,7 @@ void VectorAnimationThread::SleepThread::Run()
   while(!mDestroyThread)
   {
     bool                                               needToSleep;
-    std::chrono::time_point<std::chrono::system_clock> sleepTimePoint;
+    std::chrono::time_point<std::chrono::steady_clock> sleepTimePoint;
 
     {
       ConditionalWait::ScopedLock lock(mConditionalWait);
@@ -330,7 +330,7 @@ void VectorAnimationThread::SleepThread::Run()
     if(needToSleep)
     {
 #if defined(DEBUG_ENABLED)
-      auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::system_clock::now());
+      auto sleepDuration = std::chrono::duration_cast<std::chrono::milliseconds>(mSleepTimePoint - std::chrono::steady_clock::now());
 
       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count());
 #endif
index 86fec43..8190e7b 100644 (file)
@@ -139,7 +139,7 @@ private:
     /**
      * @brief Sleeps untile the specified time point.
      */
-    void SleepUntil(std::chrono::time_point<std::chrono::system_clock> timeToSleepUntil);
+    void SleepUntil(std::chrono::time_point<std::chrono::steady_clock> timeToSleepUntil);
 
   protected:
     /**
@@ -154,7 +154,7 @@ private:
   private:
     ConditionalWait                                    mConditionalWait;
     std::unique_ptr<CallbackBase>                      mAwakeCallback;
-    std::chrono::time_point<std::chrono::system_clock> mSleepTimePoint;
+    std::chrono::time_point<std::chrono::steady_clock> mSleepTimePoint;
     const Dali::LogFactoryInterface&                   mLogFactory;
     bool                                               mNeedToSleep;
     bool                                               mDestroyThread;