[Dali-toolkit] Restrict text ui handles to prevent going outside Text Controls 37/246137/13
authorSara Samara <sarasamara@review.tizen.org>
Sun, 25 Oct 2020 11:27:27 +0000 (14:27 +0300)
committerSara Samara <sara.samara@samsung.com>
Mon, 22 Mar 2021 12:18:19 +0000 (14:18 +0200)
Steps to generate the issue:
1- Highlight the text in the TextEditor and grab the selection handle. Or you can drag the single handle without selecting the text.
2- Drag it to the right, left, up or down.
3- Notice how it goes outside of the TextEditor bounds.

//Demo Code:
***********

using namespace Dali;
using namespace Dali::Toolkit;

class SimpleApp : public ConnectionTracker
{
public:
  SimpleApp(Application& application)
  : mApplication(application)
  {
    mApplication.InitSignal().Connect(this, &SimpleApp::Create);
  }

  void Create(Application& application)
  {
    Window window = application.GetWindow();
    const float       TOOLBAR_HEIGHT_PERCENTAGE = 0.05f;
    window.SetBackgroundColor(Vector4(0.04f, 0.345f, 0.392f, 1.0f));
    const Vector2 windowSize = window.GetSize();
    const float                 toolBarHeight = TOOLBAR_HEIGHT_PERCENTAGE * windowSize.height;
    const Vector3     TEXT_EDITOR_RELATIVE_SIZE(0.9f, 0.5f, 1.0f);
    const Vector4     TEXT_EDITOR_BACKGROUND_COLOR(1.f, 1.f, 1.f, 0.15f);

    mEditor = TextEditor::New();
    mEditor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::POSITION, Vector3(0.f, toolBarHeight * 2.0f, 0.f));
    mEditor.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
    mEditor.SetProperty(Actor::Property::SIZE_MODE_FACTOR, TEXT_EDITOR_RELATIVE_SIZE);

    mEditor.SetBackgroundColor(TEXT_EDITOR_BACKGROUND_COLOR);

    const Size boundingBoxSize(windowSize * TEXT_EDITOR_RELATIVE_SIZE.GetVectorXY());
    Rect<int>  boundingBox(0,
                          static_cast<int>(toolBarHeight),
                          static_cast<int>(boundingBoxSize.width),
                          static_cast<int>(boundingBoxSize.height - toolBarHeight));

    mEditor.SetProperty(TextEditor::Property::DECORATION_BOUNDING_BOX, boundingBox);
    mEditor.SetProperty(TextEditor::Property::TEXT_COLOR, Color::BLACK);
    mEditor.SetProperty(TextEditor::Property::TEXT,
                        "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
                        "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
                        "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
                        "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
                        "Quidam corpora at duo. An eos possim scripserit?\n\n"
                        "Aťqui dicant sěnťenťíae aň vel!\n"
                        "Vis viris médiocrem elaboraret ét, verear civibus moderatius ex duo!\n"
                        "Án veri laborě iňtěgré quó, mei aď poššit lobortis, mei prompťa čonsťitůťó eů.\n"
                        "Aliquip sanctůs delicáta quí ěá, et natum aliquam est?\n"
                        "Asšúm sapěret usu ůť.\n"
                        "Síť ut apeirián laboramúš percipitur, sůas hařum ín éos?\n");

    window.Add(mEditor);
  }

private:
  Application& mApplication;
  TextEditor mEditor;
};

int DALI_EXPORT_API main(int argc, char** argv)
{
  Application application = Application::New(&argc, &argv);
  SimpleApp test(application);
  application.MainLoop();

  return 0;
}

***********

[Dali-toolkit] Restrict text ui handles to prevent going outside Text Controls

Change-Id: Iaf4d7daed106a2404e6d4ea5953e7a132dd1905f

dali-toolkit/internal/text/decorator/text-decorator.cpp

index 237649a..c586deb 100644 (file)
@@ -971,10 +971,7 @@ struct Decorator::Impl : public ConnectionTracker
     // The SetGrabHandleImage() method will change the orientation.
     const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
 
-    if(grabHandle.actor)
-    {
-      grabHandle.actor.SetProperty(Actor::Property::POSITION, Vector2(grabHandle.position.x + floor(0.5f * mCursorWidth) + (mSmoothHandlePanEnabled ? grabHandle.grabDisplacementX : 0.f), yLocalPosition + (mSmoothHandlePanEnabled ? grabHandle.grabDisplacementY : 0.f)));
-    }
+    ApplyDisplacement(grabHandle, yLocalPosition);
   }
 
   void SetSelectionHandlePosition(HandleType type)
@@ -1063,10 +1060,47 @@ struct Decorator::Impl : public ConnectionTracker
     // The SetHandleImage() method will change the orientation.
     const float yLocalPosition = handle.verticallyFlipped ? handle.position.y : handle.position.y + handle.lineHeight;
 
-    if(handle.actor)
+    ApplyDisplacement(handle, yLocalPosition);
+  }
+
+  void ApplyDisplacement(HandleImpl& handle, float yLocalPosition)
+  {
+    if( handle.actor )
+    {
+      float adjustedDisplacementX = 0.0f;
+      float adjustedDisplacementY = 0.0f;
+      if (mSmoothHandlePanEnabled)
+      {
+        adjustedDisplacementX = CalculateAdjustedDisplacement(handle.position.x, handle.grabDisplacementX, mControlSize.x);
+        adjustedDisplacementY = CalculateAdjustedDisplacement(handle.position.y, handle.grabDisplacementY, (mControlSize.y - handle.lineHeight));
+      }
+      handle.actor.SetProperty(Actor::Property::POSITION,
+                               Vector2(handle.position.x + floor(0.5f * mCursorWidth) + adjustedDisplacementX,
+                                       yLocalPosition + adjustedDisplacementY));
+    }
+  }
+
+  float CalculateAdjustedDisplacement(float position, float displacement, float edge)
+  {
+    //Apply the displacement (on the X-axis & the Y-axis)
+    //as long as it does not exceed the control's edge.
+    float adjustedDisplacement = 0.0f;
+    if(position + displacement < 0.0f)
+    {
+      // -position to cancel it out and relocate to 0.
+      adjustedDisplacement = -position;
+    }
+    else if(position + displacement > edge)
+    {
+      // move in a displacement which is sufficient to reach the edge.
+      adjustedDisplacement = edge - position;
+    }
+    else
     {
-      handle.actor.SetProperty(Actor::Property::POSITION, Vector2(handle.position.x + (mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f), yLocalPosition + (mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f)));
+      // move normally in the displacement.
+      adjustedDisplacement = displacement;
     }
+    return adjustedDisplacement;
   }
 
   void SetHandleImage(HandleType type)