[dali_2.3.23] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-event-handler.cpp
index e351342..99cc227 100644 (file)
 #include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
 #include <dali/devel-api/adaptor-framework/key-devel.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
 #include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
 #include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
 
 namespace
@@ -36,11 +36,13 @@ namespace
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
 #endif
 
-const std::string KEY_C_NAME      = "c";
-const std::string KEY_V_NAME      = "v";
-const std::string KEY_X_NAME      = "x";
-const std::string KEY_A_NAME      = "a";
-const std::string KEY_INSERT_NAME = "Insert";
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
+
+const char* KEY_C_NAME      = "c";
+const char* KEY_V_NAME      = "v";
+const char* KEY_X_NAME      = "x";
+const char* KEY_A_NAME      = "a";
+const char* KEY_INSERT_NAME = "Insert";
 
 } // namespace
 
@@ -191,6 +193,12 @@ bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyE
         return false;
       }
 
+      if(controller.mImpl->mEventData->mState == EventData::INACTIVE)
+      {
+        // Cursor position will be updated
+        controller.mImpl->ChangeState(EventData::EDITING);
+      }
+
       controller.mImpl->mEventData->mCheckScrollAmount = true;
       Event event(Event::CURSOR_KEY_EVENT);
       event.p1.mInt  = keyCode;
@@ -213,8 +221,11 @@ bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyE
       bool consumed = false;
       if(keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME || logicalKey == KEY_C_NAME || logicalKey == KEY_INSERT_NAME)
       {
-        // Ctrl-C or Ctrl+Insert to copy the selected text
-        controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::COPY);
+        if(!keyEvent.IsRepeat())
+        {
+          // Ctrl-C or Ctrl+Insert to copy the selected text
+          controller.TextPopupButtonTouched(Toolkit::TextSelectionPopup::COPY);
+        }
         consumed = true;
       }
       else if(keyName == KEY_V_NAME || logicalKey == KEY_V_NAME)
@@ -368,27 +379,54 @@ void Controller::EventHandler::AnchorEvent(Controller& controller, float x, floa
   CharacterIndex cursorPosition = 0u;
 
   // Convert from control's coords to text's coords.
+
   const float xPosition = x - controller.mImpl->mModel->mScrollPosition.x;
   const float yPosition = y - controller.mImpl->mModel->mScrollPosition.y;
 
+  Vector2 visualTransformOffset = controller.mImpl->mModel->mVisualTransformOffset;
+
   // Whether to touch point hits on a glyph.
   bool matchedCharacter = false;
   cursorPosition        = Text::GetClosestCursorIndex(controller.mImpl->mModel->mVisualModel,
                                                controller.mImpl->mModel->mLogicalModel,
                                                controller.mImpl->mMetrics,
                                                xPosition,
-                                               yPosition,
+                                               yPosition - visualTransformOffset.y,
                                                CharacterHitTest::TAP,
                                                matchedCharacter);
 
-  for(const auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors)
+  for(auto& anchor : controller.mImpl->mModel->mLogicalModel->mAnchors)
   {
     // Anchor clicked if the calculated cursor position is within the range of anchor.
     if(cursorPosition >= anchor.startIndex && cursorPosition < anchor.endIndex)
     {
-      if(controller.mImpl->mAnchorControlInterface && anchor.href)
+      if(controller.mImpl->mAnchorControlInterface)
       {
-        std::string href(anchor.href);
+        if(!anchor.isClicked)
+        {
+          anchor.isClicked = true;
+          // TODO: in mutable text, the anchor color and underline run index should be able to be updated.
+          if(!controller.IsEditable())
+          {
+            // If there is a markup clicked color attribute, use it. Otherwise, use the property color.
+            if(controller.mImpl->mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
+            {
+              ColorRun& colorRun = *(controller.mImpl->mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
+              colorRun.color = anchor.isMarkupClickedColorSet ? anchor.markupClickedColor : controller.mImpl->mAnchorClickedColor;
+            }
+            if(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
+            {
+              UnderlinedCharacterRun& underlineRun = *(controller.mImpl->mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
+              underlineRun.properties.color = anchor.isMarkupClickedColorSet ? anchor.markupClickedColor : controller.mImpl->mAnchorClickedColor;
+            }
+
+            controller.mImpl->ClearFontData();
+            controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
+            controller.mImpl->RequestRelayout();
+          }
+        }
+
+        std::string href = anchor.href == nullptr ? "" : anchor.href;
         controller.mImpl->mAnchorControlInterface->AnchorClicked(href);
         break;
       }
@@ -598,6 +636,8 @@ void Controller::EventHandler::ProcessModifyEvents(Controller& controller)
     return;
   }
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_MODIFY_EVENTS");
+
   for(Vector<ModifyEvent>::ConstIterator it    = events.Begin(),
                                          endIt = events.End();
       it != endIt;
@@ -728,13 +768,13 @@ bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode)
   else if((controller.mImpl->mEventData->mPrimaryCursorPosition > 0) && (keyCode == Dali::DALI_KEY_BACKSPACE))
   {
     // Remove the character before the current cursor position
-    removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE);
+    removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE, false);
   }
   else if((controller.mImpl->mEventData->mPrimaryCursorPosition < controller.mImpl->mModel->mLogicalModel->mText.Count()) &&
           (keyCode == Dali::DevelKey::DALI_KEY_DELETE))
   {
     // Remove the character after the current cursor position
-    removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE);
+    removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE, false);
   }
 
   if(removed)
@@ -785,7 +825,8 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
       const bool textDeleted = TextUpdater::RemoveText(controller,
                                                        inputMethodContextEvent.cursorOffset,
                                                        inputMethodContextEvent.numberOfChars,
-                                                       DONT_UPDATE_INPUT_STYLE);
+                                                       DONT_UPDATE_INPUT_STYLE,
+                                                       false);
 
       if(textDeleted)
       {
@@ -821,7 +862,7 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
     case InputMethodContext::SELECTION_SET:
     {
       uint32_t start = static_cast<uint32_t>(inputMethodContextEvent.startIndex);
-      uint32_t end = static_cast<uint32_t>(inputMethodContextEvent.endIndex);
+      uint32_t end   = static_cast<uint32_t>(inputMethodContextEvent.endIndex);
       if(start == end)
       {
         controller.SetPrimaryCursorPosition(start, true);
@@ -848,22 +889,10 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
 
   std::string    text;
   CharacterIndex cursorPosition      = 0u;
-  Length         numberOfWhiteSpaces = 0u;
 
   if(retrieveCursor)
   {
-    numberOfWhiteSpaces = controller.mImpl->GetNumberOfWhiteSpaces(0u);
-
     cursorPosition = controller.mImpl->GetLogicalCursorPosition();
-
-    if(cursorPosition < numberOfWhiteSpaces)
-    {
-      cursorPosition = 0u;
-    }
-    else
-    {
-      cursorPosition -= numberOfWhiteSpaces;
-    }
   }
 
   if(retrieveText)
@@ -871,7 +900,7 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
     if(!controller.mImpl->IsShowingPlaceholderText())
     {
       // Retrieves the normal text string.
-      controller.mImpl->GetText(numberOfWhiteSpaces, text);
+      controller.mImpl->GetText(0u, text);
     }
     else
     {
@@ -893,12 +922,8 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
   return callbackData;
 }
 
-void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller)
+void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller, const std::string& text)
 {
-  // Retrieve the clipboard contents first
-  ClipboardEventNotifier notifier(ClipboardEventNotifier::Get());
-  std::string            stringToPaste(notifier.GetContent());
-
   // Commit the current pre-edit text; the contents of the clipboard should be appended
   controller.mImpl->ResetInputMethodContext();
 
@@ -906,7 +931,7 @@ void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller)
   controller.mImpl->SetClipboardHideEnable(false);
 
   // Paste
-  TextUpdater::PasteText(controller, stringToPaste);
+  TextUpdater::PasteText(controller, text);
 
   controller.mImpl->SetClipboardHideEnable(true);
 }