Merge "Fix: The last line of the text overlaps with the text-editor's border/edge...
authorBowon Ryu <bowon.ryu@samsung.com>
Tue, 16 Nov 2021 09:27:48 +0000 (09:27 +0000)
committerGerrit Code Review <gerrit@review>
Tue, 16 Nov 2021 09:27:48 +0000 (09:27 +0000)
89 files changed:
automated-tests/src/dali-scene-loader/utc-Dali-StringCallback.cpp
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.cpp
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-canvas-renderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ArcVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-CanvasView.cpp
automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-Transition.cpp
dali-toolkit/devel-api/controls/accessible-impl.cpp
dali-toolkit/devel-api/controls/accessible-impl.h
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/toolkit-action-index-ranges.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h
dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h
dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h [deleted file]
dali-toolkit/devel-api/visuals/image-visual-actions-devel.h
dali-toolkit/devel-api/visuals/visual-actions-devel.h [moved from dali-toolkit/devel-api/visuals/color-visual-actions-devel.h with 60% similarity]
dali-toolkit/internal/controls/canvas-view/canvas-view-impl.cpp
dali-toolkit/internal/controls/canvas-view/canvas-view-impl.h
dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.cpp
dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp
dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp
dali-toolkit/internal/controls/gl-view/gl-view-impl.h
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
dali-toolkit/internal/controls/table-view/table-view-impl.cpp
dali-toolkit/internal/controls/text-controls/common-text-utils.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/common-text-utils.h [new file with mode: 0644]
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-editor-property-handler.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-field-property-handler.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/text/multi-language-support-impl.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/text-controller-impl-model-updater.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-impl-model-updater.h [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/transition/transition-base-impl.cpp
dali-toolkit/internal/transition/transition-base-impl.h
dali-toolkit/internal/transition/transition-impl.cpp
dali-toolkit/internal/transition/transition-impl.h
dali-toolkit/internal/transition/transition-set-impl.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/arc/arc-visual.cpp
dali-toolkit/internal/visuals/arc/arc-visual.h
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.h
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/control-impl.h
dali-toolkit/public-api/controls/gl-view/gl-view.cpp
dali-toolkit/public-api/controls/gl-view/gl-view.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/transition/transition.cpp
dali-toolkit/public-api/transition/transition.h
dali-toolkit/styles/1920x1080_rpi/dali-toolkit-default-theme.json [new file with mode: 0644]
dali-toolkit/styles/1920x1080_rpi/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_right.png [new file with mode: 0644]
packaging/dali-toolkit.spec

index acd5183..113f40a 100644 (file)
@@ -41,6 +41,6 @@ int UtcDaliUtilsDefaultStringCallback(void)
 {
   InstallLogFunction(TestLogFunction);
   DefaultErrorCallback("Hello world!");
-  DALI_TEST_EQUAL(std::string(sBuffer), "2: DefaultErrorCallback Hello world!");
+  DALI_TEST_EQUAL(std::string(sBuffer), "2: string-callback.cpp: DefaultErrorCallback(26) > Hello world!");
   END_TEST;
 }
index a9d9f03..b654d52 100644 (file)
 #include <dali/devel-api/adaptor-framework/accessibility-impl.h>
 #include "dbus-wrapper.h"
 
-namespace Dali {
-    namespace Accessibility {
-
-        using MethodType = TestDBusWrapper::MethodType;
-        using MessagePtr = DBusWrapper::MessagePtr;
-
-        static bool MoveOutedCalled = false;
-
-        void TestEnableSC(bool b) {
-            static bool firstTime = true;
-            if (b && firstTime) {
-                firstTime = false;
-                auto bridge = Accessibility::Bridge::GetCurrentBridge();
-                Dali::Stage stage = Dali::Stage::GetCurrent();
-                auto accessible = Accessibility::Accessible::Get( stage.GetRootLayer() );
-//                bridge->SetApplicationChild( accessible ); // BART
-                bridge->AddTopLevelWindow( accessible ); // BART
-                bridge->SetApplicationName( "TestApp" );
-                bridge->Initialize();
-
-                static bool ScreenReaderEnabled = false;
-                static bool IsEnabled = false;
-
-                auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr {
-                    auto reply = wr->newReplyMessage(m);
-                    wr->Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ ScreenReaderEnabled });
-                    return reply;
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr {
-                    auto reply = wr->newReplyMessage(m);
-                    wr->Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ IsEnabled });
-                    return reply;
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Bus", "GetAddress", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr {
-                    auto reply = wr->newReplyMessage(m);
-                    wr->Encode(reply, std::tuple<const char*>{ "bus" });
-                    return reply;
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible/root", "org.a11y.atspi.Socket", "Embed", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr {
-                    auto reply = wr->newReplyMessage(m);
-                    wr->Encode(reply, std::tuple<Address>{ {"bus", "root"} });
-                    return reply;
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "PropertyChange", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "StateChanged", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "BoundsChanged", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "ActiveDescendantChanged", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextChanged", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextCaretMoved", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    return wr->newReplyMessage(m);
-                };
-                wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "MoveOuted", MethodType::Method}] =
-                [wr](const MessagePtr &m) -> MessagePtr {
-                    MoveOutedCalled = true;
-                    return wr->newReplyMessage(m);
-                };
-            }
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", b);
-            wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "IsEnabled", b);
-        }
-
-        std::vector<Address> TestGetChildren(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<std::vector<Address>>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildren", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetName(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto name = wr->fromTestGet<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "Name");
-            return name;
-        }
-
-        std::string TestGetDescription(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto description = wr->fromTestGet<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "Description");
-            return description;
-        }
-
-        uint32_t TestGetRole(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<uint32_t>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRole", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetRoleName(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRoleName", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        Address TestGetParent(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestGet< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "Parent");
-            return chs;
-        }
-
-        std::string TestGetLocalizedRoleName(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetLocalizedRoleName", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::array< uint32_t, 2 > TestGetStates(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<std::array< uint32_t, 2 >>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetState", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall<std::unordered_map< std::string, std::string >>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetAttributes", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Accessible", "DoGesture",
-                std::tuple< Dali::Accessibility::Gesture, int32_t, int32_t, int32_t, int32_t, Dali::Accessibility::GestureState, uint32_t >(type, xBeg, xEnd, yBeg, yEnd, state, eventTime ));
-            return std::move(std::get<0>(chs));
-        }
-
-        std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRelationSet", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        Address TestGetChildAtIndex(const Address &adr, int index)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildAtIndex", std::tuple< int >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        ComponentLayer TestGetLayer(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< Dali::Accessibility::ComponentLayer >(adr.GetPath(), "org.a11y.atspi.Component", "GetLayer", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        int TestGetIndexInParent(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< int >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetIndexInParent", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        bool TestGrabFocus(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabFocus", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        bool TestGrabHighlight(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabHighlight", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        bool TestClearHighlight(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "ClearHighlight", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr, Dali::Accessibility::CoordinateType coordinateType)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::tuple< int32_t, int32_t, int32_t, int32_t > >(adr.GetPath(), "org.a11y.atspi.Component", "GetExtents", std::make_tuple(static_cast<uint32_t>(coordinateType)));
-            return std::move(std::get<0>(chs));
-        }
-
-        int TestGetMdiZOrder(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< int16_t >(adr.GetPath(), "org.a11y.atspi.Component", "GetMDIZOrder", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        double TestGetAlpha(const Address &adr)
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< double >(adr.GetPath(), "org.a11y.atspi.Component", "GetAlpha", std::tuple<>());
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetActionName( const Address &adr, size_t index )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetName", std::tuple< int32_t >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetLocalizedActionName( const Address &adr, size_t index )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetLocalizedName", std::tuple< int32_t >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        size_t TestGetActionCount( const Address &adr )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto count = wr->fromTestGet< int32_t >(adr.GetPath(), "org.a11y.atspi.Action", "NActions");
-            return count;
-        }
-
-        bool TestDoAction ( const Address &adr, size_t index )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoAction", std::tuple< int32_t >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        bool TestDoAction ( const Address &adr, const std::string& name )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoActionName", std::tuple< std::string >( name ));
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetActionKeyBinding ( const Address &adr, size_t index )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetKeyBinding", std::tuple< int32_t >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        std::string TestGetActionDescription ( const Address &adr, size_t index )
-        {
-            auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
-            auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetDescription", std::tuple< int32_t >( index ));
-            return std::move(std::get<0>(chs));
-        }
-
-        void TestResetMoveOutedCalled ()
-        {
-          MoveOutedCalled = false;
-        }
-
-        bool TestGetMoveOutedCalled ()
-        {
-          return MoveOutedCalled;
-        }
-
-        void printTree(const Address &root, size_t depth)
-        {
-            auto name = TestGetName(root);
-            printf("%10s", root.GetPath().c_str());
-            for(unsigned int i = 0; i < depth; ++i) printf("  ");
-            printf("%s\n", name.c_str());
-            auto chs = TestGetChildren(root);
-            for(auto &c : chs)
-                printTree(c, depth + 1);
-        }
-
-        bool Find( const std::vector< std::string > &collection, const std::string &key)
-        {
-            for ( auto& it : collection)
-                if( it == key )
-                    return true;
-            return false;
-        }
+namespace Dali
+{
+namespace Accessibility
+{
+  using MethodType = TestDBusWrapper::MethodType;
+  using MessagePtr = DBusWrapper::MessagePtr;
+
+  static bool gMoveOutedCalled = false;
+
+  void TestEnableSC(bool b)
+  {
+    static bool firstTime = true;
+    if (b && firstTime)
+    {
+      firstTime = false;
+      auto bridge = Accessibility::Bridge::GetCurrentBridge();
+      Dali::Stage stage = Dali::Stage::GetCurrent();
+      auto accessible = Accessibility::Accessible::Get( stage.GetRootLayer(), true );
+      bridge->AddTopLevelWindow( accessible );
+      bridge->SetApplicationName( "TestApp" );
+      bridge->Initialize();
+
+      static bool ScreenReaderEnabled = false;
+      static bool IsEnabled = false;
+
+      auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr {
+          auto reply = wr->newReplyMessage(m);
+          wr->Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ ScreenReaderEnabled });
+          return reply;
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr {
+          auto reply = wr->newReplyMessage(m);
+          wr->Encode(reply, std::tuple<TestDBusWrapper::Variant<bool>>{ IsEnabled });
+          return reply;
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/bus", "org.a11y.Bus", "GetAddress", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr {
+          auto reply = wr->newReplyMessage(m);
+          wr->Encode(reply, std::tuple<const char*>{ "bus" });
+          return reply;
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible/root", "org.a11y.atspi.Socket", "Embed", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr {
+          auto reply = wr->newReplyMessage(m);
+          wr->Encode(reply, std::tuple<Address>{ {"bus", "root"} });
+          return reply;
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "PropertyChange", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "StateChanged", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "BoundsChanged", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "ActiveDescendantChanged", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextChanged", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextCaretMoved", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          return wr->newReplyMessage(m);
+      };
+      wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "MoveOuted", MethodType::Method}] =
+      [wr](const MessagePtr &m) -> MessagePtr {
+          gMoveOutedCalled = true;
+          return wr->newReplyMessage(m);
+      };
     }
-}
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", b);
+    wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "IsEnabled", b);
+  }
+
+  std::vector<Address> TestGetChildren(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<std::vector<Address>>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildren", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetName(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto name = wr->fromTestGet<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "Name");
+    return name;
+  }
+
+  std::string TestGetDescription(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto description = wr->fromTestGet<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "Description");
+    return description;
+  }
+
+  uint32_t TestGetRole(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<uint32_t>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRole", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetRoleName(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRoleName", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  Address TestGetParent(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestGet< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "Parent");
+    return chs;
+  }
+
+  std::string TestGetLocalizedRoleName(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<std::string>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetLocalizedRoleName", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::array< uint32_t, 2 > TestGetStates(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<std::array< uint32_t, 2 >>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetState", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall<std::unordered_map< std::string, std::string >>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetAttributes", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Accessible", "DoGesture",
+        std::tuple< Dali::Accessibility::Gesture, int32_t, int32_t, int32_t, int32_t, Dali::Accessibility::GestureState, uint32_t >(type, xBeg, xEnd, yBeg, yEnd, state, eventTime ));
+    return std::move(std::get<0>(chs));
+  }
+
+  std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRelationSet", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  Address TestGetChildAtIndex(const Address &adr, int index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildAtIndex", std::tuple< int >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  ComponentLayer TestGetLayer(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< Dali::Accessibility::ComponentLayer >(adr.GetPath(), "org.a11y.atspi.Component", "GetLayer", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  int TestGetIndexInParent(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< int >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetIndexInParent", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  bool TestGrabFocus(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabFocus", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  bool TestGrabHighlight(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabHighlight", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  bool TestClearHighlight(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "ClearHighlight", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr, Dali::Accessibility::CoordinateType coordinateType)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::tuple< int32_t, int32_t, int32_t, int32_t > >(adr.GetPath(), "org.a11y.atspi.Component", "GetExtents", std::make_tuple(static_cast<uint32_t>(coordinateType)));
+    return std::move(std::get<0>(chs));
+  }
+
+  int TestGetMdiZOrder(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< int16_t >(adr.GetPath(), "org.a11y.atspi.Component", "GetMDIZOrder", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  double TestGetAlpha(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< double >(adr.GetPath(), "org.a11y.atspi.Component", "GetAlpha", std::tuple<>());
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetActionName(const Address &adr, size_t index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetName", std::tuple< int32_t >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetLocalizedActionName(const Address &adr, size_t index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetLocalizedName", std::tuple< int32_t >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  size_t TestGetActionCount(const Address &adr)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto count = wr->fromTestGet< int32_t >(adr.GetPath(), "org.a11y.atspi.Action", "NActions");
+    return count;
+  }
+
+  bool TestDoAction(const Address &adr, size_t index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoAction", std::tuple< int32_t >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  bool TestDoAction(const Address &adr, const std::string& name)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoActionName", std::tuple< std::string >( name ));
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetActionKeyBinding(const Address &adr, size_t index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetKeyBinding", std::tuple< int32_t >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  std::string TestGetActionDescription(const Address &adr, size_t index)
+  {
+    auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
+    auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetDescription", std::tuple< int32_t >( index ));
+    return std::move(std::get<0>(chs));
+  }
+
+  void TestResetMoveOutedCalled ()
+  {
+    gMoveOutedCalled = false;
+  }
+
+  bool TestGetMoveOutedCalled ()
+  {
+    return gMoveOutedCalled;
+  }
+
+  void PrintTree(const Address &root, size_t depth)
+  {
+    auto name = TestGetName(root);
+    printf("%10s", root.GetPath().c_str());
+    for(unsigned int i = 0; i < depth; ++i) printf("  ");
+    printf("%s\n", name.c_str());
+    auto chs = TestGetChildren(root);
+    for(auto &c : chs)
+    {
+      PrintTree(c, depth + 1);
+    }
+  }
+
+  bool Find(const std::vector< std::string > &collection, const std::string &key)
+  {
+    for(auto& it : collection)
+    {
+      if(it == key)
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+} // namespace Accessibility
+} // namespace Dali
index 6c172fd..92388e2 100644 (file)
@@ -3,42 +3,43 @@
 
 #include <dali/devel-api/adaptor-framework/accessibility.h>
 
-
-namespace Dali {
-    namespace Accessibility {
-        void TestEnableSC(bool b);
-        std::vector<Address> TestGetChildren(const Address &adr);
-        std::string TestGetName(const Address &adr);
-        std::string TestGetDescription(const Address &adr);
-        uint32_t TestGetRole(const Address &adr);
-        std::string TestGetRoleName(const Address &adr);
-        Address TestGetParent(const Address &adr);
-        std::string TestGetLocalizedRoleName(const Address &adr);
-        std::array< uint32_t, 2 > TestGetStates(const Address &adr);
-        std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr);
-        bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime);
-        std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr);
-        Address TestGetChildAtIndex(const Address &adr, int index);
-        ComponentLayer TestGetLayer(const Address &adr);
-        int TestGetIndexInParent(const Address &adr);
-        bool TestGrabFocus(const Address &adr);
-        bool TestGrabHighlight(const Address &adr);
-        bool TestClearHighlight(const Address &adr);
-        std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr, Dali::Accessibility::CoordinateType coordinateType );
-        int TestGetMdiZOrder(const Address &adr);
-        double TestGetAlpha(const Address &adr);
-        void printTree(const Address &root, size_t depth = 0);
-        bool Find( const std::vector< std::string > &collection, const std::string &key);
-        std::string TestGetActionName( const Address &adr, size_t index );
-        std::string TestGetLocalizedActionName( const Address &adr, size_t index );
-        size_t TestGetActionCount( const Address &adr );
-        bool TestDoAction ( const Address &adr, size_t index );
-        bool TestDoAction ( const Address &adr, const std::string& name );
-        std::string TestGetActionKeyBinding ( const Address &adr, size_t index );
-        std::string TestGetActionDescription ( const Address &adr, size_t index );
-        void TestResetMoveOutedCalled ();
-        bool TestGetMoveOutedCalled ();
-    }
-}
+namespace Dali
+{
+namespace Accessibility
+{
+  void TestEnableSC(bool b);
+  std::vector<Address> TestGetChildren(const Address &adr);
+  std::string TestGetName(const Address &adr);
+  std::string TestGetDescription(const Address &adr);
+  uint32_t TestGetRole(const Address &adr);
+  std::string TestGetRoleName(const Address &adr);
+  Address TestGetParent(const Address &adr);
+  std::string TestGetLocalizedRoleName(const Address &adr);
+  std::array< uint32_t, 2 > TestGetStates(const Address &adr);
+  std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr);
+  bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime);
+  std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr);
+  Address TestGetChildAtIndex(const Address &adr, int index);
+  ComponentLayer TestGetLayer(const Address &adr);
+  int TestGetIndexInParent(const Address &adr);
+  bool TestGrabFocus(const Address &adr);
+  bool TestGrabHighlight(const Address &adr);
+  bool TestClearHighlight(const Address &adr);
+  std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr, Dali::Accessibility::CoordinateType coordinateType );
+  int TestGetMdiZOrder(const Address &adr);
+  double TestGetAlpha(const Address &adr);
+  void PrintTree(const Address &root, size_t depth = 0);
+  bool Find( const std::vector< std::string > &collection, const std::string &key);
+  std::string TestGetActionName( const Address &adr, size_t index );
+  std::string TestGetLocalizedActionName( const Address &adr, size_t index );
+  size_t TestGetActionCount( const Address &adr );
+  bool TestDoAction ( const Address &adr, size_t index );
+  bool TestDoAction ( const Address &adr, const std::string& name );
+  std::string TestGetActionKeyBinding ( const Address &adr, size_t index );
+  std::string TestGetActionDescription ( const Address &adr, size_t index );
+  void TestResetMoveOutedCalled ();
+  bool TestGetMoveOutedCalled ();
+} // namespace Accessibility
+} // namespace Dali
 
 #endif //__DALI_TOOLKIT_ACCESSIBILITY_TEST_UTILS__
index 0b1ec0e..047018d 100644 (file)
@@ -1157,6 +1157,7 @@ int UtcDaliAccessibilityScrollToChildNonScrollable(void)
 
   DALI_TEST_EQUALS(accessible->IsScrollable(), false, TEST_LOCATION);
   DALI_TEST_EQUALS(accessible->ScrollToChild({}), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(accessible->GetInternalActor(), Dali::Actor{}, TEST_LOCATION);
 
   Dali::Accessibility::TestEnableSC( false );
   END_TEST;
index 5e69c95..440270a 100644 (file)
@@ -19,6 +19,8 @@
 
 namespace Dali
 {
+const Rect<int> TestApplication::DEFAULT_SURFACE_RECT = Rect<int>(0, 0, TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT);
+
 bool TestApplication::mLoggingEnabled = true;
 
 TestApplication::TestApplication(uint32_t surfaceWidth,
@@ -225,7 +227,7 @@ bool TestApplication::PreRenderWithPartialUpdate(uint32_t intervalMilliseconds,
 
 bool TestApplication::RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
 {
-  mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/, clippingRect);
+  mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/, clippingRect);
   mCore->PostRender(false /*do not skip rendering*/);
 
index 4f32cd8..02143a7 100644 (file)
@@ -38,6 +38,8 @@ public:
   static const uint32_t DEFAULT_SURFACE_WIDTH  = 480;
   static const uint32_t DEFAULT_SURFACE_HEIGHT = 800;
 
+  static const Rect<int> DEFAULT_SURFACE_RECT;
+
   static constexpr uint32_t DEFAULT_HORIZONTAL_DPI = 220;
   static constexpr uint32_t DEFAULT_VERTICAL_DPI   = 217;
 
index 56c0cd8..43aa8ce 100644 (file)
@@ -39,7 +39,7 @@ class CanvasRenderer: public Dali::BaseObject
 public:
   CanvasRenderer( const Vector2& size )
   : mDrawable(nullptr),
-    mPixelBuffer( Devel::PixelBuffer::New(size.width, size.height, Dali::Pixel::RGBA8888) ),
+    mTexture ( Dali::Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, size.width, size.height ) ),
     mSize(size),
     mViewBox(size)
   {
@@ -59,6 +59,11 @@ public:
      return true;
   }
 
+  Dali::Texture GetRasterizedTexture()
+  {
+    return mTexture;
+  }
+
   bool Rasterize()
   {
      return true;
@@ -97,12 +102,6 @@ public:
     return false;
   }
 
-  Devel::PixelBuffer GetPixelBuffer()
-  {
-    return mPixelBuffer;
-  }
-
-
   bool SetSize(Vector2 size)
   {
     mSize = size;
@@ -137,7 +136,7 @@ public:
 
 public:
    Dali::CanvasRenderer::Drawable* mDrawable;
-   Devel::PixelBuffer mPixelBuffer;
+   Dali::Texture mTexture;
    Vector2 mSize;
    Vector2 mViewBox;
 };
@@ -200,9 +199,9 @@ bool CanvasRenderer::Rasterize()
   return Internal::Adaptor::GetImplementation(*this).Rasterize();
 }
 
-Devel::PixelBuffer CanvasRenderer::GetPixelBuffer()
+Dali::Texture CanvasRenderer::GetRasterizedTexture()
 {
-  return Internal::Adaptor::GetImplementation(*this).GetPixelBuffer();
+  return Internal::Adaptor::GetImplementation(*this).GetRasterizedTexture();
 }
 
 bool CanvasRenderer::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
index 7f43240..1eb713e 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
@@ -707,7 +708,7 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
 
   attributes.Clear();
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -746,7 +747,7 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
 
   attributes.Clear();
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -825,7 +826,7 @@ int UtcDaliAnimatedVectorImageVisualPlayRangeMarker(void)
 
   attributes.Clear();
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -849,7 +850,7 @@ int UtcDaliAnimatedVectorImageVisualPlayRangeMarker(void)
 
   attributes.Clear();
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -956,7 +957,7 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
 
   Property::Map attributes;
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
 
@@ -979,7 +980,7 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
   array.PushBack( 4 );
 
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   attributes.Clear();
   DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
@@ -1074,7 +1075,7 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
   attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 5 );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -1100,7 +1101,7 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
 
   attributes.Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -1125,7 +1126,7 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
 
   attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 10 );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
@@ -1176,7 +1177,7 @@ int UtcDaliAnimatedVectorImageVisualStopBehavior(void)
   // Change stop behavior
   attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   attributes.Clear();
 
@@ -1201,7 +1202,7 @@ int UtcDaliAnimatedVectorImageVisualStopBehavior(void)
   attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::CURRENT_FRAME );
   attributes.Add( DevelImageVisual::Property::LOOP_COUNT, -1 );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   attributes.Clear();
 
@@ -1271,7 +1272,7 @@ int UtcDaliAnimatedVectorImageVisualLoopingMode(void)
   // Change stop behavior
   attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::CURRENT_FRAME );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   // Play again
   DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
@@ -1289,7 +1290,7 @@ int UtcDaliAnimatedVectorImageVisualLoopingMode(void)
   // Change looping mode
   attributes.Add( DevelImageVisual::Property::LOOPING_MODE, DevelImageVisual::LoopingMode::RESTART );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   // Play again
   DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
@@ -1418,8 +1419,8 @@ int UtcDaliAnimatedVectorImageVisualMultipleInstances(void)
   Property::Map attributes;
   attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME );
 
-  DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
-  DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map() );
 
index 583ce16..146a1b5 100644 (file)
@@ -22,7 +22,7 @@
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h>
-#include <dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 #include "dummy-control.h"
 
@@ -307,7 +307,7 @@ int UtcDaliArcVisualUpdateProperty(void)
             .Add( DevelArcVisual::Property::START_ANGLE, startAngle )
             .Add( DevelArcVisual::Property::SWEEP_ANGLE, sweepAngle );
 
-  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelArcVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes );
 
   application.SendNotification();
   application.Render();
index 36cf1df..cee41e0 100644 (file)
@@ -302,42 +302,6 @@ int UtcDaliCanvasViewRasterizeTaskGetCanvasViewP(void)
   END_TEST;
 }
 
-int UtcDaliCanvasViewRasterizeTaskGetBufferSizeP(void)
-{
-  ToolkitTestApplication application;
-
-  Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100,100));
-  DALI_TEST_CHECK( dummyInternalCanvasView );
-
-  Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
-  DALI_TEST_CHECK( dummyCanvasRenderer );
-
-  IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
-  DALI_TEST_CHECK( task );
-
-  //There is no rasterized buffer.
-  DALI_TEST_EQUALS( task->GetBufferSize(), Vector2(0, 0), TEST_LOCATION );
-
-  END_TEST;
-}
-
-int UtcDaliCanvasViewRasterizeTaskGetPixelDataP(void)
-{
-
-  Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100,100));
-  DALI_TEST_CHECK( dummyInternalCanvasView );
-
-  Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
-  DALI_TEST_CHECK( dummyCanvasRenderer );
-
-  IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
-  DALI_TEST_CHECK( task );
-
-  DALI_TEST_EQUALS( task->GetPixelData(), PixelData(), TEST_LOCATION );
-
-  END_TEST;
-}
-
 int UtcDaliCanvasViewRasterizeThreadP(void)
 {
   ToolkitTestApplication application;
@@ -488,13 +452,13 @@ int UtcDaliCanvasViewRasterizeThreadRasterizationCompletedSignalP(void)
 {
   ToolkitTestApplication application;
 
-  Dali::Toolkit::Internal::CanvasView* dummyInternalCanvasView = new Dali::Toolkit::Internal::CanvasView(Vector2(100,100));
-  DALI_TEST_CHECK( dummyInternalCanvasView );
+  Dali::Toolkit::CanvasView canvasView = Dali::Toolkit::CanvasView::New(Vector2(100, 100));
+  Dali::Toolkit::Internal::CanvasView& dummyInternalCanvasView = GetImpl(canvasView);
 
   Dali::CanvasRenderer dummyCanvasRenderer = Dali::CanvasRenderer::New(Vector2(100, 100));
   DALI_TEST_CHECK( dummyCanvasRenderer );
 
-  IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(dummyInternalCanvasView, dummyCanvasRenderer);
+  IntrusivePtr<Dali::Toolkit::Internal::CanvasRendererRasterizingTask> task = new Dali::Toolkit::Internal::CanvasRendererRasterizingTask(&dummyInternalCanvasView, dummyCanvasRenderer);
   DALI_TEST_CHECK( task );
 
   Dali::Toolkit::Internal::CanvasViewRasterizeThread *dummyThread = new Dali::Toolkit::Internal::CanvasViewRasterizeThread();
@@ -504,10 +468,10 @@ int UtcDaliCanvasViewRasterizeThreadRasterizationCompletedSignalP(void)
 
   dummyThread->Process(false);
 
-  PixelData pixelData = CreatePixelData( 100, 100 );
+  auto texture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, 100, 100 );
 
-  dummyThread->RasterizationCompletedSignal().Connect(dummyInternalCanvasView, &Dali::Toolkit::Internal::CanvasView::ApplyRasterizedImage);
-  dummyThread->RasterizationCompletedSignal().Emit(pixelData);
+  dummyThread->RasterizationCompletedSignal().Connect(&dummyInternalCanvasView, &Dali::Toolkit::Internal::CanvasView::ApplyRasterizedImage);
+  dummyThread->RasterizationCompletedSignal().Emit(texture);
 
   application.SendNotification();
   application.Render();
index 9f74b72..9cefe16 100644 (file)
@@ -181,15 +181,15 @@ void resizeCB(Vector2 size)
 {
 }
 
-int UtcDaliGlViewRegisterGlCallbackN(void)
+int UtcDaliGlViewRegisterGlCallbacksN(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcDaliGlViewRegisterGlCallback");
+  tet_infoline("UtcDaliGlViewRegisterGlCallbacksN");
   GlView view;
 
   try
   {
-    view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+    view.RegisterGlCallbacks(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
     DALI_TEST_CHECK(false);
   }
   catch(...)
@@ -243,7 +243,7 @@ int UtcDaliGlViewWindowVisibilityChanged(void)
   application.GetScene().Add( view );
   view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
   view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
-  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+  view.RegisterGlCallbacks(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
   view.SetResizeCallback(Dali::MakeCallback(resizeCB));
 
   application.SendNotification();
@@ -268,7 +268,7 @@ int UtcDaliGlViewOnScene(void)
   application.GetScene().Add( view );
   view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
   view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
-  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+  view.RegisterGlCallbacks(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
 
   application.SendNotification();
   application.Render();
@@ -314,7 +314,7 @@ int UtcDaliGlViewResize(void)
 
   application.GetScene().Add( view );
   view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
-  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+  view.RegisterGlCallbacks(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
   view.SetResizeCallback(Dali::MakeCallback(resizeCB));
   view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
   view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f));
index 5495c9d..c9453e1 100644 (file)
@@ -836,6 +836,13 @@ int UtcDaliToolkitTextLabelEmojisP(void)
   application.SendNotification();
   application.Render();
 
+  // EMOJI + ZWJ + EMOJI case for coverage.
+  const std::string emojiWithZWJ = "&#x1f469;&#x200d;&#x1f52c;";
+  label.SetProperty( TextLabel::Property::TEXT, emojiWithZWJ );
+
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
index 7e36d2c..0ead710 100755 (executable)
@@ -24,6 +24,8 @@
 #include <dali-toolkit/public-api/transition/transition-set.h>
 #include <dali-toolkit/public-api/transition/transition-base.h>
 #include <dali-toolkit/public-api/transition/transition.h>
+#include <dali-toolkit/public-api/transition/fade-transition.h>
+#include <dali-toolkit/public-api/transition/slide-transition.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -118,7 +120,7 @@ int UtcDaliTransitionSetGetProperty01(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(-0.1f, -0.1f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(-0.1f, -0.1f));
   TimePeriod timePeriod = transition.GetTimePeriod();
   DALI_TEST_EQUALS(0.0f, timePeriod.durationSeconds, TEST_LOCATION);
   DALI_TEST_EQUALS(0.0f, timePeriod.delaySeconds, TEST_LOCATION);
@@ -178,7 +180,7 @@ int UtcDaliTransitionSetGetProperty02(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(-0.1f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(-0.1f));
   TimePeriod timePeriod = transition.GetTimePeriod();
   DALI_TEST_EQUALS(0.0f, timePeriod.durationSeconds, TEST_LOCATION);
   DALI_TEST_EQUALS(0.0f, timePeriod.delaySeconds, TEST_LOCATION);
@@ -268,7 +270,7 @@ int UtcDaliTransitionBetweenControlPair(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f));
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -333,6 +335,185 @@ int UtcDaliTransitionBetweenControlPair(void)
   END_TEST;
 }
 
+int UtcDaliTransitionBetweenControlPair2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPair2 - source target will be transitioned.");
+
+  Vector3 sourcePosition(100, 200, 0);
+  Vector3 sourceSize(150, 150, 0);
+  Vector3 sourceScale(1, 2, 0);
+  Vector4 sourceColor(1.0f, 1.0f, 1.0f, 0.5f);
+  float sourceOpacity(0.5f);
+  float sourceRadius(30.f);
+  float sourceBorderlineWidth(60.0f);
+  Vector4 sourceBorderlineColor(1.0f, 0.0f, 0.0f, 1.0f);
+  float sourceBorderlineOffset(1.f);
+  Vector4 sourceRadiusV4 = Vector4(sourceRadius, sourceRadius, sourceRadius, sourceRadius);
+
+  Vector3 destinationPosition(50, 50, 0);
+  Vector3 destinationSize(120, 120, 0);
+  Vector3 destinationScale(2, 1, 0);
+  Vector4 destinationColor(1.0f, 0.5f, 1.0f, 0.8f);
+  float destinationOpacity(0.8f);
+  float destinationRadius(50.f);
+  float destinationBorderlineWidth(80.0f);
+  Vector4 destinationBorderlineColor(0.5f, 1.0f, 0.5f, 0.3f);
+  float destinationBorderlineOffset(-1.0f);
+  Vector4 destinationRadiusV4 = Vector4(destinationRadius, destinationRadius, destinationRadius, destinationRadius);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control1.SetProperty(Actor::Property::POSITION, sourcePosition);
+  control1.SetProperty(Actor::Property::SIZE, sourceSize);
+  control1.SetProperty(Actor::Property::SCALE, sourceScale);
+  control1.SetProperty(Actor::Property::COLOR, sourceColor);
+  control1.SetProperty(Actor::Property::OPACITY, sourceOpacity);
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, sourceRadius);
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, sourceBorderlineWidth);
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, sourceBorderlineColor);
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, sourceBorderlineOffset);
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control2.SetProperty(Actor::Property::SIZE, destinationSize);
+  control2.SetProperty(Actor::Property::SCALE, destinationScale);
+  control2.SetProperty(Actor::Property::COLOR, destinationColor);
+  control2.SetProperty(Actor::Property::OPACITY, destinationOpacity);
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.0f, 0.5f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, destinationRadius);
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, destinationBorderlineWidth);
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, destinationBorderlineColor);
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, destinationBorderlineOffset);
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  Property::Map backgroundMap = control2.GetProperty<Property::Map>(Toolkit::Control::Property::BACKGROUND);
+  Vector4 cornerRadius = backgroundMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationRadiusV4, cornerRadius, TEST_LOCATION);
+  float borderlineWidth = backgroundMap.Find(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH)->Get<float>();
+  DALI_TEST_EQUALS(destinationBorderlineWidth, borderlineWidth, TEST_LOCATION);
+  Vector4 borderlineColor = backgroundMap.Find(Toolkit::DevelVisual::Property::BORDERLINE_COLOR)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationBorderlineColor, borderlineColor, TEST_LOCATION);
+  float borderlineOffset = backgroundMap.Find(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET)->Get<float>();
+  DALI_TEST_EQUALS(destinationBorderlineOffset, borderlineOffset, TEST_LOCATION);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, false, TimePeriod(0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(50);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  DALI_TEST_NOT_EQUALS(destinationPosition, control1.GetCurrentProperty<Vector3>(Actor::Property::POSITION), 0.00001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(1, control1.GetRendererCount(), TEST_LOCATION);
+
+  Dali::Renderer renderer = control1.GetRendererAt(0);
+  Property::Index index = renderer.GetPropertyIndex(DevelVisual::Property::CORNER_RADIUS);
+  cornerRadius = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_NOT_EQUALS(destinationRadiusV4, cornerRadius, 0.00001f, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_WIDTH);
+  borderlineWidth = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_NOT_EQUALS(destinationBorderlineWidth, borderlineWidth, 0.00001f, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_COLOR);
+  borderlineColor = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_NOT_EQUALS(destinationBorderlineColor, borderlineColor, 0.00001f, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_OFFSET);
+  borderlineOffset = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_NOT_EQUALS(destinationBorderlineOffset, borderlineOffset, 0.00001f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(700);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  // After the transition is finished,
+  // every current and renderer propeties of control1 are equal to destination properties.
+  DALI_TEST_EQUALS(destinationPosition, control1.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationSize, control1.GetCurrentProperty<Vector3>(Actor::Property::SIZE), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationScale, control1.GetCurrentProperty<Vector3>(Actor::Property::SCALE), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationColor, control1.GetCurrentProperty<Vector4>(Actor::Property::COLOR), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationOpacity, control1.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(1, control1.GetRendererCount(), TEST_LOCATION);
+  renderer = control1.GetRendererAt(0);
+  index = renderer.GetPropertyIndex(DevelVisual::Property::CORNER_RADIUS);
+  cornerRadius = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_EQUALS(destinationRadiusV4, cornerRadius, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_WIDTH);
+  borderlineWidth = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_EQUALS(destinationBorderlineWidth, borderlineWidth, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_COLOR);
+  borderlineColor = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_EQUALS(destinationBorderlineColor, borderlineColor, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_OFFSET);
+  borderlineOffset = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_EQUALS(destinationBorderlineOffset, borderlineOffset, TEST_LOCATION);
+
+  // every actor properties of control1 are returned to the source properties.
+  DALI_TEST_EQUALS(sourcePosition, control1.GetProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  DALI_TEST_EQUALS(sourceSize, control1.GetProperty<Vector3>(Actor::Property::SIZE), TEST_LOCATION);
+  DALI_TEST_EQUALS(sourceScale, control1.GetProperty<Vector3>(Actor::Property::SCALE), TEST_LOCATION);
+  DALI_TEST_EQUALS(sourceColor, control1.GetProperty<Vector4>(Actor::Property::COLOR), TEST_LOCATION);
+  DALI_TEST_EQUALS(sourceOpacity, control1.GetProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(20);
+
+  // after next update, renderer properties are returned to the source properties.
+  DALI_TEST_EQUALS(1, control1.GetRendererCount(), TEST_LOCATION);
+  renderer = control1.GetRendererAt(0);
+  index = renderer.GetPropertyIndex(DevelVisual::Property::CORNER_RADIUS);
+  cornerRadius = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_EQUALS(sourceRadiusV4, cornerRadius, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_WIDTH);
+  borderlineWidth = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_EQUALS(sourceBorderlineWidth, borderlineWidth, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_COLOR);
+  borderlineColor = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_EQUALS(sourceBorderlineColor, borderlineColor, TEST_LOCATION);
+
+  index = renderer.GetPropertyIndex(DevelVisual::Property::BORDERLINE_OFFSET);
+  borderlineOffset = renderer.GetCurrentProperty<float>(index);
+  DALI_TEST_EQUALS(sourceBorderlineOffset, borderlineOffset, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliTransitionBetweenControlPairWithoutEmptySourceBackground(void)
 {
   ToolkitTestApplication application;
@@ -377,7 +558,7 @@ int UtcDaliTransitionBetweenControlPairWithoutEmptySourceBackground(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f));
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -474,7 +655,7 @@ int UtcDaliTransitionBetweenImageViewPair(void)
   Vector3 startWorldPosition = control1.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
   Vector3 finishWorldPosition = control2.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f));
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -562,7 +743,7 @@ int UtcDaliTransitionBetweenImageViewPairWithDelay(void)
   Vector3 startWorldPosition = control1.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
   Vector3 finishWorldPosition = control2.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f, 0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f, 0.5f));
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -654,7 +835,7 @@ int UtcDaliTransitionBetweenControlPairWithTree(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f));
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -721,7 +902,7 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithChild(void)
   application.SendNotification();
   application.Render(20);
 
-  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  Transition transition = Transition::New(control1, control2, true, TimePeriod(0.5f));
   transition.TransitionWithChild(true);
   TransitionSet transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
@@ -801,7 +982,7 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithoutPositionInheritance(void)
   control3.SetProperty(Actor::Property::INHERIT_ORIENTATION, true);
   control3.SetProperty(Actor::Property::INHERIT_SCALE, true);
 
-  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transition = Transition::New(control1, control3, true, TimePeriod(0.5f));
   transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -892,7 +1073,7 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithoutOrientationInheritance(voi
   bool signalReceived(false);
   TransitionFinishCheck finishCheck(signalReceived);
 
-  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transition = Transition::New(control1, control3, true, TimePeriod(0.5f));
   transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -978,7 +1159,7 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithoutScaleInheritance(void)
   bool signalReceived(false);
   TransitionFinishCheck finishCheck(signalReceived);
 
-  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transition = Transition::New(control1, control3, true, TimePeriod(0.5f));
   transitionSet = TransitionSet::New();
   transitionSet.AddTransition(transition);
   transitionSet.Play();
@@ -1007,3 +1188,82 @@ int UtcDaliTransitionBetweenControlPairWithTreeWithoutScaleInheritance(void)
 
   END_TEST;
 }
+
+
+int UtcDaliMultipleTransitionAppearing(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliMultipleTransitionAppearing");
+
+  Control control = Control::New();
+  control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty;
+  controlProperty.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty);
+
+  application.GetScene().Add(control);
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(1.0f, control.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  TransitionSet transitionSet = TransitionSet::New();
+  FadeTransition fade = FadeTransition::New(control, 0.5, TimePeriod(1.0f, 1.0f));
+  fade.SetAppearingTransition(true); // set fade in
+  transitionSet.AddTransition(fade);
+  SlideTransition slide = SlideTransition::New(control, Dali::Toolkit::SlideTransitionDirection::BOTTOM, TimePeriod(0.5f, 1.0f));
+  slide.SetAppearingTransition(true); // set slide
+  transitionSet.AddTransition(slide);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(300);
+
+  float currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity == 0.0f);
+
+  application.SendNotification();
+  application.Render(400);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity == 0.5f);
+
+  application.SendNotification();
+  application.Render(500);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity > 0.5f && currentOpacity < 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+
+  currentOpacity = control.GetCurrentProperty<float>(Actor::Property::OPACITY);
+  DALI_TEST_CHECK(currentOpacity > 0.5f && currentOpacity < 1.0f);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  application.SendNotification();
+  application.Render(500);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(1.0f, control.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+
+  END_TEST;
+}
index 9f1c78e..9f6f4f9 100644 (file)
@@ -363,7 +363,6 @@ void AccessibleImpl::ScrollToSelf()
       parent->ScrollToChild(child->Self());
     }
 
-    child = parent;
     parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(parent->GetParent());
   }
 }
@@ -542,6 +541,11 @@ std::vector<Dali::Accessibility::Relation> AccessibleImpl::GetRelationSet()
   return ret;
 }
 
+Dali::Actor AccessibleImpl::GetInternalActor()
+{
+  return Dali::Actor{};
+}
+
 bool AccessibleImpl::ScrollToChild(Actor child)
 {
   return false;
index aa5084a..8bd0714 100644 (file)
@@ -226,12 +226,17 @@ public:
   std::vector<Dali::Accessibility::Relation> GetRelationSet() override;
 
   /**
+   * @copydoc Dali::Accessibility::Accessible::GetInternalActor()
+   */
+  Dali::Actor GetInternalActor() override;
+
+  /**
    * @copydoc Dali::Accessibility::Accessible::GetStates()
    */
   virtual Dali::Accessibility::States CalculateStates();
 
   /**
-   * @brief Makes sure that a given child of this container (e.g. ItemView) is visible
+   * @brief Makes sure that a given child (descendant) of this container (e.g. ItemView) is visible
    * @return false if scrolling is not supported or child is already visible
    */
   virtual bool ScrollToChild(Actor child);
index 55becb3..dc7a128 100644 (file)
@@ -122,19 +122,6 @@ Dali::Property GetVisualProperty(Control control, Dali::Property::Index index, D
   return controlDataImpl.GetVisualProperty(index, visualPropertyKey);
 }
 
-void CreateTransitions(Control control, Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
-{
-  if(animation)
-  {
-    // make visual transition of control visual.
-    Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
-    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(internalControl);
-    controlDataImpl.MakeVisualTransition(animation, source, Toolkit::Control::Property::BACKGROUND, alphaFunction, timePeriod);
-    controlDataImpl.MakeVisualTransition(animation, source, Toolkit::DevelControl::Property::SHADOW, alphaFunction, timePeriod);
-    internalControl.OnCreateTransitions(animation, source, alphaFunction, timePeriod);
-  }
-}
-
 static Toolkit::Internal::Control::Impl* GetControlImplementation(Dali::Actor actor)
 {
   Dali::Toolkit::Control control = Toolkit::Control::DownCast(actor);
index 36b83f9..8877646 100644 (file)
@@ -371,20 +371,6 @@ DALI_TOOLKIT_API VisualEventSignalType& VisualEventSignal(Control control);
 DALI_TOOLKIT_API Dali::Property GetVisualProperty(Control control, Dali::Property::Index index, Dali::Property::Key visualPropertyKey);
 
 /**
- * @brief Retrieve visual/renderer property animation between this Control and source control.
- * Input animation must be created before this method called.
- * And the animations between this method created are added the input animation.
- * This method generates visual/renderer property animation but not creates Actor property animation.
- *
- * @param[in] control The control
- * @param[in] animation generated animation
- * @param[in] source source control of the animation.
- * @param[in] alphaFunction AlphaFunction of the animation
- * @param[in] timePeriod TimePeriod of the animation
- */
-DALI_TOOLKIT_API void CreateTransitions(Control control, Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod);
-
-/**
  * @brief The signal is emmited as a succession of "activate" signal send by accessibility client.
  * @return The signal to connect to
  */
index e94f60b..c88b7a0 100755 (executable)
@@ -77,6 +77,7 @@ SET( devel_api_src_files
 SET( devel_api_header_files
   ${devel_api_src_dir}/direction-enums.h
   ${devel_api_src_dir}/toolkit-property-index-ranges.h
+  ${devel_api_src_dir}/toolkit-action-index-ranges.h
 )
 
 SET( devel_api_accessibility-manager_header_files
@@ -168,13 +169,12 @@ SET( devel_api_visuals_header_files
   ${devel_api_src_dir}/visuals/animated-image-visual-actions-devel.h
   ${devel_api_src_dir}/visuals/animated-vector-image-visual-actions-devel.h
   ${devel_api_src_dir}/visuals/animated-vector-image-visual-signals-devel.h
-  ${devel_api_src_dir}/visuals/arc-visual-actions-devel.h
   ${devel_api_src_dir}/visuals/arc-visual-properties-devel.h
-  ${devel_api_src_dir}/visuals/color-visual-actions-devel.h
   ${devel_api_src_dir}/visuals/color-visual-properties-devel.h
   ${devel_api_src_dir}/visuals/image-visual-properties-devel.h
   ${devel_api_src_dir}/visuals/image-visual-actions-devel.h
   ${devel_api_src_dir}/visuals/text-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/visual-actions-devel.h
   ${devel_api_src_dir}/visuals/visual-properties-devel.h
 )
 
diff --git a/dali-toolkit/devel-api/toolkit-action-index-ranges.h b/dali-toolkit/devel-api/toolkit-action-index-ranges.h
new file mode 100644 (file)
index 0000000..8e5dbc4
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_TOOLKIT_ACTION_INDEX_RANGES_H
+#define DALI_TOOLKIT_ACTION_INDEX_RANGES_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-index-ranges.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+/**
+ * @brief Enumeration for the start and end action ranges.
+ */
+enum ActionRanges
+{
+  VISUAL_ACTION_BASE_START_INDEX = 0,                                    ///< Visual Action Base Start Index.
+  VISUAL_ACTION_BASE_END_INDEX   = VISUAL_ACTION_BASE_START_INDEX + 100, ///< Visual Action Base End Index.
+  VISUAL_ACTION_START_INDEX      = VISUAL_ACTION_BASE_END_INDEX + 1,     ///< Visual Action Start Index.
+  VISUAL_ACTION_END_INDEX        = VISUAL_ACTION_START_INDEX + 100000,   ///< Visual Action End Index.
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ACTION_INDEX_RANGES_H
index dbe9631..94ae63c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
  * limitations under the License.
  *
  */
+#include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
 
 namespace Dali
 {
@@ -34,10 +35,10 @@ namespace Action
  */
 enum Type
 {
-  PLAY,   ///< Play the animated GIF. This is also Default playback mode.
-  PAUSE,  ///< Pause the animated GIF.
-  STOP,   ///< Stop the animated GIF.
-  JUMP_TO ///< Jump to the specified frame. Property::INTEGER value should be passed.
+  PLAY = VISUAL_ACTION_START_INDEX, ///< Play the animated GIF. This is also Default playback mode.
+  PAUSE,                            ///< Pause the animated GIF.
+  STOP,                             ///< Stop the animated GIF.
+  JUMP_TO                           ///< Jump to the specified frame. Property::INTEGER value should be passed.
 };
 
 } // namespace Action
index 2955d17..ecb91ae 100644 (file)
@@ -17,6 +17,7 @@
  * limitations under the License.
  *
  */
+#include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
 
 namespace Dali
 {
@@ -34,11 +35,10 @@ namespace Action
  */
 enum Type
 {
-  PLAY,           ///< Play the animated vector image.
-  PAUSE,          ///< Pause the animated vector image.
-  STOP,           ///< Stop the animated vector image. This is also Default playback mode.
-  JUMP_TO,        ///< Jump to the specified frame. Property::INTEGER value should be passed.
-  UPDATE_PROPERTY ///< Update the properties of the animated vector image.
+  PLAY = VISUAL_ACTION_START_INDEX, ///< Play the animated vector image.
+  PAUSE,                            ///< Pause the animated vector image.
+  STOP,                             ///< Stop the animated vector image. This is also Default playback mode.
+  JUMP_TO,                          ///< Jump to the specified frame. Property::INTEGER value should be passed.
 };
 
 } // namespace Action
diff --git a/dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h b/dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h
deleted file mode 100644 (file)
index 9657084..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_ARC_VISUAL_ACTIONS_DEVEL_H
-#define DALI_TOOLKIT_DEVEL_API_VISUALS_ARC_VISUAL_ACTIONS_DEVEL_H
-
-/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace Toolkit
-{
-namespace DevelArcVisual
-{
-/**
- * @brief Actions that the arc visual can perform.  These actions are called through the Visual::Base::DoAction API.
- */
-namespace Action
-{
-/**
- * @brief The available actions for this visual
- */
-enum Type
-{
-  /**
-   * @brief Update the properties of the visual.
-   * @note DevelArcVisual::Property::THICKNESS, DevelArcVisual::Property::START_ANGLE and DevelArcVisual::Property::SWEEP_ANGLE can be updated.
-   */
-  UPDATE_PROPERTY = 0
-};
-
-} // namespace Action
-
-} // namespace DevelArcVisual
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_ARC_VISUAL_ACTIONS_DEVEL_H
index 89ea2d6..66b4715 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_ACTIONS_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
  * limitations under the License.
  *
  */
+#include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
 
 namespace Dali
 {
@@ -34,7 +35,7 @@ namespace Action
  */
 enum Type
 {
-  RELOAD = 0 ///< Force reloading of the image, all visuals using this image will get the latest one.
+  RELOAD = VISUAL_ACTION_START_INDEX ///< Force reloading of the image, all visuals using this image will get the latest one.
 };
 
 } // namespace Action
@@ -1,8 +1,8 @@
-#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_COLOR_VISUAL_ACTIONS_DEVEL_H
-#define DALI_TOOLKIT_DEVEL_API_VISUALS_COLOR_VISUAL_ACTIONS_DEVEL_H
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_ACTIONS_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_ACTIONS_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
+
 namespace Dali
 {
 namespace Toolkit
 {
-namespace DevelColorVisual
+namespace DevelVisual
 {
+
 /**
- * @brief Actions that the color visual can perform. These actions are called through the Visual::Base::DoAction API.
+ * @brief Actions that the visual can perform. These actions are called through the Visual::Base::DoAction API.
  */
 namespace Action
 {
@@ -37,15 +41,15 @@ enum Type
   /**
    * @brief Update the properties of the visual.
    */
-  UPDATE_PROPERTY = 0
+  UPDATE_PROPERTY = VISUAL_ACTION_BASE_START_INDEX
 };
 
 } // namespace Action
 
-} // namespace DevelColorVisual
+} // namespace DevelVisual
 
 } // namespace Toolkit
 
 } // namespace Dali
 
-#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_COLOR_VISUAL_ACTIONS_DEVEL_H
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_ACTIONS_DEVEL_H
index 5741a42..e8fefbf 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/rendering/texture-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-devel.h>
@@ -196,43 +197,25 @@ void CanvasView::AddRasterizationTask()
   }
 }
 
-void CanvasView::ApplyRasterizedImage(PixelData rasterizedPixelData)
+void CanvasView::ApplyRasterizedImage(Texture rasterizedTexture)
 {
-  if(rasterizedPixelData)
+  if (rasterizedTexture && rasterizedTexture.GetWidth() != 0 && rasterizedTexture.GetHeight() != 0)
   {
-    auto rasterizedPixelDataWidth  = rasterizedPixelData.GetWidth();
-    auto rasterizedPixelDataHeight = rasterizedPixelData.GetHeight();
-
-    if(rasterizedPixelDataWidth > 0 && rasterizedPixelDataHeight > 0)
+    if(!mTextureSet)
     {
-      if(!mTexture || mTexture.GetWidth() != rasterizedPixelDataWidth || mTexture.GetHeight() != rasterizedPixelDataHeight)
-      {
-        mTexture = Texture::New(TextureType::TEXTURE_2D, rasterizedPixelData.GetPixelFormat(), rasterizedPixelDataWidth, rasterizedPixelDataHeight);
-        mTexture.Upload(rasterizedPixelData);
+      std::string fragmentShader = SHADER_CANVAS_VIEW_FRAG.data();
+      DevelTexture::ApplyNativeFragmentShader(rasterizedTexture, fragmentShader);
 
-        if(!mTextureSet)
-        {
-          mTextureSet       = TextureSet::New();
-          Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
-          Shader   shader   = Shader::New(SHADER_CANVAS_VIEW_VERT, SHADER_CANVAS_VIEW_FRAG);
-          Renderer renderer = Renderer::New(geometry, shader);
-          renderer.SetTextures(mTextureSet);
-          renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
-
-          Actor actor = Self();
-          if(actor)
-          {
-            actor.AddRenderer(renderer);
-          }
-        }
-        mTextureSet.SetTexture(0, mTexture);
-      }
-      else
-      {
-        //Update texture
-        mTexture.Upload(rasterizedPixelData);
-      }
+      mTextureSet       = TextureSet::New();
+      Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
+      Shader   shader   = Shader::New(SHADER_CANVAS_VIEW_VERT, fragmentShader);
+      Renderer renderer = Renderer::New(geometry, shader);
+
+      renderer.SetTextures(mTextureSet);
+      renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
+      Self().AddRenderer(renderer);
     }
+    mTextureSet.SetTexture(0, rasterizedTexture);
   }
 
   //If there are accumulated changes to CanvasRenderer during Rasterize, Rasterize once again.
index 6b6cf93..4e492eb 100644 (file)
@@ -135,9 +135,9 @@ public:
   /**
    * @bried Apply the rasterized image to the canvas view
    *
-   * @param[in] rasterizedPixelData The pixel buffer with the rasterized pixels
+   * @param[in] rasterizedTexture The texture with the rasterized pixels
    */
-  void ApplyRasterizedImage(PixelData rasterizedPixelData);
+  void ApplyRasterizedImage(Texture rasterizedTexture);
 
 private:
   CanvasView(const CanvasView&) = delete;
index 97835c5..ba3daae 100644 (file)
@@ -31,8 +31,7 @@ namespace Internal
 CanvasRendererRasterizingTask::CanvasRendererRasterizingTask(CanvasView* canvasView, CanvasRenderer canvasRenderer)
 : mCanvasView(canvasView),
   mCanvasRenderer(canvasRenderer),
-  mPixelData(PixelData()),
-  mBufferSize(0, 0)
+  mRasterizedTexture()
 {
 }
 
@@ -40,17 +39,7 @@ bool CanvasRendererRasterizingTask::Rasterize()
 {
   if(mCanvasRenderer && mCanvasRenderer.Rasterize())
   {
-    Devel::PixelBuffer pixbuf = mCanvasRenderer.GetPixelBuffer();
-    auto               width  = pixbuf.GetWidth();
-    auto               height = pixbuf.GetHeight();
-    if(width > 0 && height > 0)
-    {
-      mBufferSize.width  = width;
-      mBufferSize.height = height;
-
-      mPixelData = Devel::PixelBuffer::Convert(pixbuf);
-      return true;
-    }
+    return true;
   }
   return false;
 }
@@ -60,14 +49,9 @@ CanvasView* CanvasRendererRasterizingTask::GetCanvasView() const
   return mCanvasView.Get();
 }
 
-PixelData CanvasRendererRasterizingTask::GetPixelData() const
-{
-  return mPixelData;
-}
-
-Vector2 CanvasRendererRasterizingTask::GetBufferSize() const
+Texture CanvasRendererRasterizingTask::GetRasterizedTexture()
 {
-  return mBufferSize;
+  return mCanvasRenderer.GetRasterizedTexture();
 }
 
 CanvasViewRasterizeThread::CanvasViewRasterizeThread()
@@ -220,7 +204,7 @@ void CanvasViewRasterizeThread::ApplyRasterized()
 {
   while(CanvasRendererRasterizingTaskPtr task = NextCompletedTask())
   {
-    RasterizationCompletedSignal().Emit(task->GetPixelData());
+    RasterizationCompletedSignal().Emit(task->GetRasterizedTexture()); // Here texture get
   }
 
   UnregisterProcessor();
index 0c16fd9..f89bb91 100644 (file)
@@ -25,7 +25,6 @@
 #include <dali/devel-api/threading/thread.h>
 #include <dali/integration-api/adaptor-framework/log-factory-interface.h>
 #include <dali/public-api/common/intrusive-ptr.h>
-#include <dali/public-api/images/pixel-data.h>
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/rendering/texture-set.h>
 #include <memory>
@@ -81,15 +80,9 @@ public:
 
   /**
    * Get the rasterization result.
-   * @return The pixel data with the rasterized pixels.
+   * @return The texture with the rasterized pixels.
    */
-  PixelData GetPixelData() const;
-
-  /**
-   * Get size of rasterization result.
-   * @return The size of the pixel data.
-   */
-  Vector2 GetBufferSize() const;
+  Texture GetRasterizedTexture();
 
 private:
   // Undefined
@@ -101,8 +94,7 @@ private:
 private:
   CanvasViewPtr  mCanvasView;
   CanvasRenderer mCanvasRenderer;
-  PixelData      mPixelData;
-  Vector2        mBufferSize;
+  Texture        mRasterizedTexture;
 };
 
 /**
@@ -112,7 +104,7 @@ class CanvasViewRasterizeThread : public Thread, Integration::Processor
 {
 public:
   /// @brief ApplyRasterizedImage Event signal type
-  using RasterizationCompletedSignalType = Signal<void(PixelData)>;
+  using RasterizationCompletedSignalType = Signal<void(Texture)>;
 
 public:
   /**
index f9f4376..d9a554e 100644 (file)
@@ -36,6 +36,7 @@
 #include <limits>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
@@ -506,7 +507,7 @@ Control::Impl::Impl(Control& controlImpl)
   mNeedToEmitResourceReady(false),
   mDispatchKeyEvents(true)
 {
-  Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter(
+  Dali::Accessibility::Accessible::RegisterExternalAccessibleGetter(
     [](Dali::Actor actor) -> Dali::Accessibility::Accessible* {
       return Control::Impl::GetAccessibilityObject(actor);
     });
@@ -1970,115 +1971,46 @@ Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dal
   return Dali::Property(handle, Property::INVALID_INDEX);
 }
 
-void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod)
+void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
+                                      std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
+                                      Dali::Toolkit::Control source, Dali::Toolkit::Control destination)
 {
-  Dali::Toolkit::Control sourceHandle      = Dali::Toolkit::Control::DownCast(source);
-  Property::Map          sourceMap         = sourceHandle.GetProperty<Property::Map>(visualIndex);
-  Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self());
-  Property::Map          destinationMap    = destinationHandle.GetProperty<Property::Map>(visualIndex);
-
-  Vector4 mixColor(1.0f, 1.0f, 1.0f, 1.0f);
-  Vector4 cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
-  float   borderlineWidth(0.0f);
-  Vector4 borderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
-  float   borderlineOffset(0.0f);
-
-  if(!destinationMap.Empty())
+  // Retrieves background properties to be transitioned.
+  Dali::Property::Map backgroundSourcePropertyMap, backgroundDestinationPropertyMap;
+  mControlImpl.MakeVisualTransition(backgroundSourcePropertyMap, backgroundDestinationPropertyMap, source, destination, Toolkit::Control::Property::BACKGROUND);
+  if(backgroundSourcePropertyMap.Count() > 0)
   {
-    static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 {
-      Property::Value* propertyValue = map.Find(index);
-      if(propertyValue)
-      {
-        return propertyValue->Get<Vector4>();
-      }
-      return defaultValue;
-    };
-
-    static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float {
-      Property::Value* propertyValue = map.Find(index);
-      if(propertyValue)
-      {
-        return propertyValue->Get<float>();
-      }
-      return defaultValue;
-    };
-
-    mixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
-    cornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
-    borderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
-    borderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
-    borderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
-
-    if(sourceMap.Empty())
-    {
-      sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
-      sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
-      sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
-      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
-      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
-      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
-    }
-
-    Vector4 sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
-    Vector4 sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
-    float   sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
-    Vector4 sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
-    float   sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
-
-    std::vector<Dali::Property>                              properties;
-    std::vector<std::pair<Property::Value, Property::Value>> values;
-
-    if(Vector3(sourceMixColor) != Vector3(mixColor))
-    {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR));
-      values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor)));
-    }
-
-    if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1)
-    {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY));
-      values.push_back(std::make_pair(sourceMixColor.a, mixColor.a));
-    }
-
-    if(sourceCornerRadius != cornerRadius)
-    {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS));
-      values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
-    }
+    sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundSourcePropertyMap));
+    destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundDestinationPropertyMap));
+  }
 
-    if(sourceBorderlineWidth != borderlineWidth)
-    {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH));
-      values.push_back(std::make_pair(sourceBorderlineWidth, borderlineWidth));
-    }
+  // Retrieves shadow properties to be transitioned.
+  Dali::Property::Map shadowSourcePropertyMap, shadowDestinationPropertyMap;
+  mControlImpl.MakeVisualTransition(shadowSourcePropertyMap, shadowDestinationPropertyMap, source, destination, Toolkit::DevelControl::Property::SHADOW);
+  if(shadowSourcePropertyMap.Count() > 0)
+  {
+    sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowSourcePropertyMap));
+    destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowDestinationPropertyMap));
+  }
 
-    if(sourceBorderlineColor != borderlineColor)
-    {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR));
-      values.push_back(std::make_pair(sourceBorderlineColor, borderlineColor));
-    }
+  // Retrieves transition from inherited class.
+  mControlImpl.OnCreateTransitions(sourceProperties, destinationProperties, source, destination);
+}
 
-    if(sourceBorderlineOffset != borderlineOffset)
+void Control::Impl::UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
+{
+  for(auto&& data : properties)
+  {
+    if(data.first == Toolkit::Control::Property::BACKGROUND)
     {
-      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET));
-      values.push_back(std::make_pair(sourceBorderlineOffset, borderlineOffset));
+      DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second);
     }
-
-    for(uint32_t i = 0; i < properties.size(); ++i)
+    else if(data.first == Toolkit::DevelControl::Property::SHADOW)
     {
-      if(timePeriod.delaySeconds > 0.0f)
-      {
-        Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
-        initialKeyframes.Add(0.0f, values[i].first);
-        initialKeyframes.Add(1.0f, values[i].first);
-        animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
-      }
-      Dali::KeyFrames keyframes = Dali::KeyFrames::New();
-      keyframes.Add(0.0f, values[i].first);
-      keyframes.Add(1.0f, values[i].second);
-      animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
+      DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second);
     }
   }
+  mControlImpl.OnUpdateVisualProperties(properties);
 }
 
 void Control::Impl::EmitResourceReadySignal()
index 94da0fc..55c49a6 100644 (file)
@@ -393,16 +393,32 @@ public:
   Dali::Property GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey);
 
   /**
-   * @brief Make visual transition from source control to this control about specific Property::Index
-   * If both of source and this control have Property::Index property, than create animation between them.
+   * @brief Retrieves source and destination visual properties for the Transition of this Control.
+   * The properties of this Control will be transitioned from the propeties of source Control to that of destination control.
+   * If a property value is different between source and destination Control,
+   * the property information of each Control will be included in sourceProperties and destinationProperties.
    *
-   * @param[in] animation Return animation from source to this control.
-   * @param[in] source Source control to be used property animation.
-   * @param[in] visualIndex Property::Index to make animation.
-   * @param[in] alphaFunction alpha function of the animation.
-   * @param[in] timePeriod time period of the animation.
+   * @param[out] sourceProperties Source property list to be applied on this Control.
+   * @param[out] destinationProperties Destination property list to be applied on this Control.
+   * @param[in] source Source control of the animation.
+   * @param[in] destination Destination control of the animation.
+   *
+   * @note This method do not handle Actor properties.
+   * And the size and order of the sourceProperties and destinationProperties must be synchronized.
+   *
+   * This method triggers Control::OnCreateTransition().
+   */
+  void CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
+                         std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
+                         Dali::Toolkit::Control source, Dali::Toolkit::Control destination);
+
+  /**
+   * @brief Update visual properties.
+   * @param[in] properties Property list to be used to update visual properties of this Control.
+   *
+   * @note This method triggers Control::OnUpdateVisualProperties().
    */
-  void MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod);
+  void UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties);
 
   /**
    * @brief Gets the current control's accessible object.
index a3c092d..4a3b065 100644 (file)
@@ -39,7 +39,7 @@ namespace
 // currently not called from code so compiler will optimize these away, kept here for future debugging
 
 #define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
-#define FC_LOG(fmt, args, ...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ##args)
+#define FC_LOG(fmt, args, ...) Debug::LogMessageWithFunctionLine(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ##args)
 // #define FLEX_CONTAINER_DEBUG 1
 
 #if defined(FLEX_CONTAINER_DEBUG)
index 64e31d6..b37189a 100644 (file)
@@ -67,11 +67,11 @@ GlView::~GlView()
   }
 }
 
-void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+void GlView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
 {
   if(mRenderThread)
   {
-    mRenderThread->RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback);
+    mRenderThread->RegisterGlCallbacks(initCallback, renderFrameCallback, terminateCallback);
   }
 }
 
index c0114ca..2dcb0b1 100644 (file)
@@ -55,9 +55,9 @@ public:
   GlView(Dali::Toolkit::GlView::ColorFormat colorFormat);
 
   /**
-   * @copydoc Dali::Toolkit::GlView::RegisterGlCallback()
+   * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks()
    */
-  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+  void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
 
   /**
    * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
index db2e98c..3e84cfd 100644 (file)
@@ -72,7 +72,7 @@ GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue)
   }
 }
 
-void GlViewRenderThread::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+void GlViewRenderThread::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
 {
   if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback)
   {
index c27c832..753526e 100644 (file)
@@ -54,9 +54,9 @@ public:
   virtual ~GlViewRenderThread();
 
   /**
-   * @copydoc Dali::Toolkit::GlView::RegisterGlCallback()
+   * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks()
    */
-  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+  void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
 
   /**
    * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
index e3701ec..1a653a1 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/object/type-registry.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
@@ -284,114 +285,36 @@ void ImageView::OnRelayout(const Vector2& size, RelayoutContainer& container)
   }
 }
 
-void ImageView::OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
+void ImageView::OnCreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
+                                    std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
+                                    Dali::Toolkit::Control                                              source,
+                                    Dali::Toolkit::Control                                              destination)
 {
-  Dali::Toolkit::ImageView destinationHandle = Toolkit::ImageView(GetOwner());
-  Toolkit::Visual::Base    destinationVisual = DevelControl::GetVisual(GetImplementation(destinationHandle), Toolkit::ImageView::Property::IMAGE);
-  Property::Map            destinationMap;
-
-  if(!destinationVisual)
-  {
-    return;
-  }
-
-  destinationVisual.CreatePropertyMap(destinationMap);
-
-  static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 {
-    Property::Value* propertyValue = map.Find(index);
-    if(propertyValue)
-    {
-      return propertyValue->Get<Vector4>();
-    }
-    return defaultValue;
-  };
-
-  static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float {
-    Property::Value* propertyValue = map.Find(index);
-    if(propertyValue)
-    {
-      return propertyValue->Get<float>();
-    }
-    return defaultValue;
-  };
-
-  Vector4 sourceMixColor(0.0f, 0.0f, 0.0f, 0.0f);
-  Vector4 sourceCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
-  float   sourceBorderlineWidth(0.0f);
-  Vector4 sourceBorderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
-  float   sourceBorderlineOffset(0.0f);
-  Vector4 destinationMixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, sourceMixColor);
-  Vector4 destinationCornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, sourceCornerRadius);
-  float   destinationBorderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, sourceBorderlineWidth);
-  Vector4 destinationBorderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, sourceBorderlineColor);
-  float   destinationBorderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, sourceBorderlineOffset);
-
-  Dali::Toolkit::ImageView sourceHandle = Dali::Toolkit::ImageView::DownCast(source);
-  Toolkit::Visual::Base    sourceVisual;
-  Property::Map            sourceMap;
-
-  if(sourceHandle)
-  {
-    sourceVisual = DevelControl::GetVisual(GetImplementation(sourceHandle), Toolkit::ImageView::Property::IMAGE);
-  }
-
-  if(sourceVisual)
+  // Retrieves image properties to be transitioned.
+  Dali::Property::Map imageSourcePropertyMap, imageDestinationPropertyMap;
+  MakeVisualTransition(imageSourcePropertyMap, imageDestinationPropertyMap, source, destination, Toolkit::ImageView::Property::IMAGE);
+  if(imageSourcePropertyMap.Count() > 0)
   {
-    sourceVisual.CreatePropertyMap(sourceMap);
-    sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, sourceMixColor);
-    sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, sourceCornerRadius);
-    sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, sourceBorderlineWidth);
-    sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, sourceBorderlineColor);
-    sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, sourceBorderlineOffset);
+    sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE, imageSourcePropertyMap));
+    destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE, imageDestinationPropertyMap));
   }
+}
 
-  std::vector<Dali::Property>                              properties;
-  std::vector<std::pair<Property::Value, Property::Value>> values;
-
-  if(Vector3(sourceMixColor) != Vector3(destinationMixColor))
-  {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::MIX_COLOR));
-    values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(destinationMixColor)));
-  }
-  if(std::abs(sourceMixColor.a - destinationMixColor.a) > Math::MACHINE_EPSILON_1)
-  {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY));
-    values.push_back(std::make_pair(sourceMixColor.a, destinationMixColor.a));
-  }
-  if(sourceCornerRadius != destinationCornerRadius)
-  {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::DevelVisual::Property::CORNER_RADIUS));
-    values.push_back(std::make_pair(sourceCornerRadius, destinationCornerRadius));
-  }
-  if(sourceBorderlineWidth != destinationBorderlineWidth)
-  {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH));
-    values.push_back(std::make_pair(sourceBorderlineWidth, destinationBorderlineWidth));
-  }
-  if(sourceBorderlineColor != destinationBorderlineColor)
-  {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::DevelVisual::Property::BORDERLINE_COLOR));
-    values.push_back(std::make_pair(sourceBorderlineColor, destinationBorderlineColor));
-  }
-  if(sourceBorderlineOffset != destinationBorderlineOffset)
+void ImageView::OnUpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
+{
+  Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
+  if(visual)
   {
-    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET));
-    values.push_back(std::make_pair(sourceBorderlineOffset, destinationBorderlineOffset));
-  }
+    Dali::Toolkit::Control handle(GetOwner());
 
-  for(uint32_t i = 0; i < properties.size(); ++i)
-  {
-    if(timePeriod.delaySeconds > 0.0f)
+    for(auto&& data : properties)
     {
-      Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
-      initialKeyframes.Add(0.0f, values[i].first);
-      initialKeyframes.Add(1.0f, values[i].first);
-      animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
+      if(data.first == Toolkit::ImageView::Property::IMAGE)
+      {
+        DevelControl::DoAction(handle, Toolkit::ImageView::Property::IMAGE, DevelVisual::Action::UPDATE_PROPERTY, data.second);
+        break;
+      }
     }
-    Dali::KeyFrames keyframes = Dali::KeyFrames::New();
-    keyframes.Add(0.0f, values[i].first);
-    keyframes.Add(1.0f, values[i].second);
-    animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
   }
 }
 
index 023930e..ef48839 100644 (file)
@@ -136,7 +136,15 @@ private: // From Control
   /**
    * @copydoc Toolkit::Control::OnCreateTransitions()
    */
-  virtual void OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod) override;
+  virtual void OnCreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
+                                   std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
+                                   Dali::Toolkit::Control                                              source,
+                                   Dali::Toolkit::Control                                              destination) override;
+
+  /**
+   * @copydoc Toolkit::Control::OnUpdateVisualProperties()
+   */
+  virtual void OnUpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties) override;
 
 private:
   /**
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp
new file mode 100644 (file)
index 0000000..24827dd
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+
+float FinalDefaultAlphaFunction(float offset)
+{
+  return offset * 0.5f;
+}
+
+/**
+ * Internal Relative position Constraint
+ * Generates the relative position value of the scroll view
+ * based on the absolute position, and it's relation to the
+ * scroll domain. This is a value from 0.0f to 1.0f in each
+ * scroll position axis.
+ */
+void InternalRelativePositionConstraint(Vector2& relativePosition, const PropertyInputContainer& inputs)
+{
+  Vector2        position = -inputs[0]->GetVector2();
+  const Vector2& min      = inputs[1]->GetVector2();
+  const Vector2& max      = inputs[2]->GetVector2();
+  const Vector3& size     = inputs[3]->GetVector3();
+
+  position.x = WrapInDomain(position.x, min.x, max.x);
+  position.y = WrapInDomain(position.y, min.y, max.y);
+
+  Vector2 domainSize = (max - min) - size.GetVectorXY();
+
+  relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
+  relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
+}
+
+/**
+ * Internal scroll domain Constraint
+ * Generates the scroll domain of the scroll view.
+ */
+void InternalScrollDomainConstraint(Vector2& scrollDomain, const PropertyInputContainer& inputs)
+{
+  const Vector2& min  = inputs[0]->GetVector2();
+  const Vector2& max  = inputs[1]->GetVector2();
+  const Vector3& size = inputs[2]->GetVector3();
+
+  scrollDomain = (max - min) - size.GetVectorXY();
+}
+
+/**
+ * Internal maximum scroll position Constraint
+ * Generates the maximum scroll position of the scroll view.
+ */
+void InternalPrePositionMaxConstraint(Vector2& scrollMax, const PropertyInputContainer& inputs)
+{
+  const Vector2& max  = inputs[0]->GetVector2();
+  const Vector3& size = inputs[1]->GetVector3();
+
+  scrollMax = max - size.GetVectorXY();
+}
+
+/**
+ * Internal Pre-Position Property Constraint.
+ *
+ * Generates position property based on current position + gesture displacement.
+ * Or generates position property based on positionX/Y.
+ * Note: This is the position prior to any clamping at scroll boundaries.
+ */
+struct InternalPrePositionConstraint
+{
+  InternalPrePositionConstraint(const Vector2&       initialPanPosition,
+                                const Vector2&       initialPanMask,
+                                bool                 axisAutoLock,
+                                float                axisAutoLockGradient,
+                                ScrollView::LockAxis initialLockAxis,
+                                const Vector2&       maxOvershoot,
+                                const RulerPtr&      rulerX,
+                                const RulerPtr&      rulerY)
+  : mLocalStart(initialPanPosition),
+    mInitialPanMask(initialPanMask),
+    mMaxOvershoot(maxOvershoot),
+    mAxisAutoLockGradient(axisAutoLockGradient),
+    mLockAxis(initialLockAxis),
+    mAxisAutoLock(axisAutoLock),
+    mWasPanning(false)
+  {
+    const RulerDomain& rulerDomainX = rulerX->GetDomain();
+    const RulerDomain& rulerDomainY = rulerY->GetDomain();
+    mDomainMin                      = Vector2(rulerDomainX.min, -rulerDomainY.min);
+    mDomainMax                      = Vector2(-rulerDomainX.max, -rulerDomainY.max);
+    mClampX                         = rulerDomainX.enabled;
+    mClampY                         = rulerDomainY.enabled;
+    mFixedRulerX                    = rulerX->GetType() == Ruler::FIXED;
+    mFixedRulerY                    = rulerY->GetType() == Ruler::FIXED;
+  }
+
+  void operator()(Vector2& scrollPostPosition, const PropertyInputContainer& inputs)
+  {
+    const Vector2& panPosition = inputs[0]->GetVector2();
+    const bool&    inGesture   = inputs[1]->GetBoolean();
+
+    // First check if we are within a gesture.
+    // The ScrollView may have received a start gesture from ::OnPan()
+    // while the finish gesture is received now in this constraint.
+    // This gesture must then be rejected as the value will be "old".
+    // Typically the last value from the end of the last gesture.
+    // If we are rejecting the gesture, we simply don't modify the constraint target.
+    if(inGesture)
+    {
+      if(!mWasPanning)
+      {
+        mPrePosition    = scrollPostPosition;
+        mStartPosition  = mPrePosition;
+        mCurrentPanMask = mInitialPanMask;
+        mWasPanning     = true;
+      }
+
+      // Calculate Deltas...
+      const Vector2& currentPosition = panPosition;
+      Vector2        panDelta(currentPosition - mLocalStart);
+
+      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
+      // appears mostly horizontal or mostly vertical respectively...
+      if(mAxisAutoLock)
+      {
+        mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
+        if(mLockAxis == ScrollView::LockVertical)
+        {
+          mCurrentPanMask.y = 0.0f;
+        }
+        else if(mLockAxis == ScrollView::LockHorizontal)
+        {
+          mCurrentPanMask.x = 0.0f;
+        }
+      }
+
+      // Restrict deltas based on ruler enable/disable and axis-lock state...
+      panDelta *= mCurrentPanMask;
+
+      // Perform Position transform based on input deltas...
+      scrollPostPosition = mPrePosition;
+      scrollPostPosition += panDelta;
+
+      // if no wrapping then clamp preposition to maximum overshoot amount
+      const Vector3& size = inputs[2]->GetVector3();
+      if(mClampX)
+      {
+        float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x);
+        if((newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1) || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1))
+        {
+          mPrePosition.x = newXPosition;
+          mLocalStart.x  = panPosition.x;
+        }
+        scrollPostPosition.x = newXPosition;
+      }
+      if(mClampY)
+      {
+        float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y);
+        if((newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1) || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1))
+        {
+          mPrePosition.y = newYPosition;
+          mLocalStart.y  = panPosition.y;
+        }
+        scrollPostPosition.y = newYPosition;
+      }
+
+      // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
+      if(mFixedRulerX || mFixedRulerY)
+      {
+        // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
+        // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
+        // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
+        // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
+        //       When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
+        //       A flick finishes before the update thread has advanced the scroll position past the previous snap point.
+        Vector2 viewPageSizeLimit(size.x - (1.0f + 1.0f), size.y - (1.0f - 1.0f));
+        Vector2 minPosition(mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y);
+        Vector2 maxPosition(mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.y);
+
+        if(mFixedRulerX)
+        {
+          scrollPostPosition.x = Clamp(scrollPostPosition.x, minPosition.x, maxPosition.x);
+        }
+        if(mFixedRulerY)
+        {
+          scrollPostPosition.y = Clamp(scrollPostPosition.y, minPosition.y, maxPosition.y);
+        }
+      }
+    }
+  }
+
+  Vector2 mPrePosition;
+  Vector2 mLocalStart;
+  Vector2 mStartPosition;  ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
+  Vector2 mInitialPanMask; ///< Initial pan mask (based on ruler settings).
+  Vector2 mCurrentPanMask; ///< Current pan mask that can be altered by axis lock mode.
+  Vector2 mDomainMin;
+  Vector2 mDomainMax;
+  Vector2 mMaxOvershoot;
+
+  float                mAxisAutoLockGradient; ///< Set by ScrollView
+  ScrollView::LockAxis mLockAxis;
+
+  bool mAxisAutoLock : 1; ///< Set by ScrollView
+  bool mWasPanning : 1;
+  bool mClampX : 1;
+  bool mClampY : 1;
+  bool mFixedRulerX : 1;
+  bool mFixedRulerY : 1;
+};
+
+/**
+ * Internal Position Property Constraint.
+ *
+ * Generates position property based on pre-position
+ * Note: This is the position after clamping.
+ * (uses result of InternalPrePositionConstraint)
+ */
+struct InternalPositionConstraint
+{
+  InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
+  : mDomainMin(-domainX.min, -domainY.min),
+    mDomainMax(-domainX.max, -domainY.max),
+    mClampX(domainX.enabled),
+    mClampY(domainY.enabled),
+    mWrap(wrap)
+  {
+  }
+
+  void operator()(Vector2& position, const PropertyInputContainer& inputs)
+  {
+    position            = inputs[0]->GetVector2();
+    const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
+    const Vector2& min  = inputs[1]->GetVector2();
+    const Vector2& max  = inputs[2]->GetVector2();
+
+    if(mWrap)
+    {
+      position.x = -WrapInDomain(-position.x, min.x, max.x);
+      position.y = -WrapInDomain(-position.y, min.y, max.y);
+    }
+    else
+    {
+      // clamp post position to domain
+      position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x) : position.x;
+      position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y) : position.y;
+    }
+  }
+
+  Vector2 mDomainMin;
+  Vector2 mDomainMax;
+  bool    mClampX;
+  bool    mClampY;
+  bool    mWrap;
+};
+
+/**
+ * This constraint updates the X overshoot property using the difference
+ * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootXConstraint
+{
+  OvershootXConstraint(float maxOvershoot)
+  : mMaxOvershoot(maxOvershoot)
+  {
+  }
+
+  void operator()(float& current, const PropertyInputContainer& inputs)
+  {
+    if(inputs[2]->GetBoolean())
+    {
+      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float          newOvershoot       = scrollPrePosition.x - scrollPostPosition.x;
+      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * This constraint updates the Y overshoot property using the difference
+ * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootYConstraint
+{
+  OvershootYConstraint(float maxOvershoot)
+  : mMaxOvershoot(maxOvershoot)
+  {
+  }
+
+  void operator()(float& current, const PropertyInputContainer& inputs)
+  {
+    if(inputs[2]->GetBoolean())
+    {
+      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float          newOvershoot       = scrollPrePosition.y - scrollPostPosition.y;
+      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * Internal Position-Delta Property Constraint.
+ *
+ * Generates position-delta property based on scroll-position + scroll-offset properties.
+ */
+void InternalPositionDeltaConstraint(Vector2& current, const PropertyInputContainer& inputs)
+{
+  const Vector2& scrollPosition = inputs[0]->GetVector2();
+  const Vector2& scrollOffset   = inputs[1]->GetVector2();
+
+  current = scrollPosition + scrollOffset;
+}
+
+/**
+ * Internal Final Position Constraint
+ * The position of content is:
+ * of scroll-position + f(scroll-overshoot)
+ * where f(...) function defines how overshoot
+ * should affect final-position.
+ */
+struct InternalFinalConstraint
+{
+  InternalFinalConstraint(AlphaFunctionPrototype functionX,
+                          AlphaFunctionPrototype functionY)
+  : mFunctionX(functionX),
+    mFunctionY(functionY)
+  {
+  }
+
+  void operator()(Vector2& current, const PropertyInputContainer& inputs)
+  {
+    const float& overshootx = inputs[1]->GetFloat();
+    const float& overshooty = inputs[2]->GetFloat();
+    Vector2      offset(mFunctionX(overshootx),
+                   mFunctionY(overshooty));
+
+    current = inputs[0]->GetVector2() - offset;
+  }
+
+  AlphaFunctionPrototype mFunctionX;
+  AlphaFunctionPrototype mFunctionY;
+};
+
+} // namespace
+
+void ScrollViewConstraints::UpdateMainInternalConstraint(ScrollView& scrollView)
+{
+  // TODO: Only update the constraints which have changed, rather than remove all and add all again.
+  // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
+  Actor              scrollViewActor = scrollView.Self();
+  PanGestureDetector detector(scrollView.GetPanGestureDetector());
+
+  if(mScrollMainInternalPositionConstraint)
+  {
+    mScrollMainInternalPositionConstraint.Remove();
+    mScrollMainInternalDeltaConstraint.Remove();
+    mScrollMainInternalFinalConstraint.Remove();
+    mScrollMainInternalRelativeConstraint.Remove();
+    mScrollMainInternalDomainConstraint.Remove();
+    mScrollMainInternalPrePositionMaxConstraint.Remove();
+  }
+  if(mScrollMainInternalPrePositionConstraint)
+  {
+    mScrollMainInternalPrePositionConstraint.Remove();
+  }
+
+  // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
+  // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
+
+  // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
+  Vector2 initialPanMask = Vector2(scrollView.mRulerX->IsEnabled() ? 1.0f : 0.0f, scrollView.mRulerY->IsEnabled() ? 1.0f : 0.0f);
+
+  if(scrollView.mLockAxis == ScrollView::LockVertical)
+  {
+    initialPanMask.y = 0.0f;
+  }
+  else if(scrollView.mLockAxis == ScrollView::LockHorizontal)
+  {
+    initialPanMask.x = 0.0f;
+  }
+
+  if(scrollView.mPanning)
+  {
+    mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>(scrollViewActor,
+                                                                        Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
+                                                                        InternalPrePositionConstraint(scrollView.mPanStartPosition,
+                                                                                                      initialPanMask,
+                                                                                                      scrollView.mAxisAutoLock,
+                                                                                                      scrollView.mAxisAutoLockGradient,
+                                                                                                      scrollView.mLockAxis,
+                                                                                                      scrollView.mMaxOvershoot,
+                                                                                                      scrollView.mRulerX,
+                                                                                                      scrollView.mRulerY));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::LOCAL_POSITION));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::PANNING));
+    mScrollMainInternalPrePositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
+    mScrollMainInternalPrePositionConstraint.Apply();
+  }
+
+  // 2. Second calculate the clamped position (actual position)
+  mScrollMainInternalPositionConstraint = Constraint::New<Vector2>(scrollViewActor,
+                                                                   Toolkit::ScrollView::Property::SCROLL_POSITION,
+                                                                   InternalPositionConstraint(scrollView.mRulerX->GetDomain(),
+                                                                                              scrollView.mRulerY->GetDomain(),
+                                                                                              scrollView.mWrapMode));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalPositionConstraint.AddSource(Source(scrollViewActor, Actor::Property::SIZE));
+  mScrollMainInternalPositionConstraint.Apply();
+
+  mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint);
+  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET));
+  mScrollMainInternalDeltaConstraint.Apply();
+
+  mScrollMainInternalFinalConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_FINAL, InternalFinalConstraint(FinalDefaultAlphaFunction, FinalDefaultAlphaFunction));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_X));
+  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_Y));
+  mScrollMainInternalFinalConstraint.Apply();
+
+  mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint);
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalRelativeConstraint.Apply();
+
+  mScrollMainInternalDomainConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint);
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalDomainConstraint.Apply();
+
+  mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint);
+  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Actor::Property::SIZE));
+  mScrollMainInternalPrePositionMaxConstraint.Apply();
+
+  // When panning we want to make sure overshoot values are affected by pre position and post position
+  SetOvershootConstraintsEnabled(scrollView, !scrollView.mWrapMode);
+}
+
+void ScrollViewConstraints::SetOvershootConstraintsEnabled(ScrollView& scrollView, bool enabled)
+{
+  Actor scrollViewActor(scrollView.Self());
+  // remove and reset, it may now be in wrong order with the main internal constraints
+  if(mScrollMainInternalOvershootXConstraint)
+  {
+    mScrollMainInternalOvershootXConstraint.Remove();
+    mScrollMainInternalOvershootXConstraint.Reset();
+    mScrollMainInternalOvershootYConstraint.Remove();
+    mScrollMainInternalOvershootYConstraint.Reset();
+  }
+  if(enabled)
+  {
+    mScrollMainInternalOvershootXConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(scrollView.mMaxOvershoot.x));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL));
+    mScrollMainInternalOvershootXConstraint.Apply();
+
+    mScrollMainInternalOvershootYConstraint = Constraint::New<float>(scrollViewActor, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(scrollView.mMaxOvershoot.y));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
+    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL));
+    mScrollMainInternalOvershootYConstraint.Apply();
+  }
+  else
+  {
+    scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
+    scrollViewActor.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
+  }
+}
+
+void ScrollViewConstraints::SetInternalConstraints(ScrollView& scrollView)
+{
+  // Internal constraints (applied to target ScrollBase Actor itself) /////////
+  UpdateMainInternalConstraint(scrollView);
+
+  // User definable constraints to apply to all child actors //////////////////
+  Actor scrollViewActor = scrollView.Self();
+
+  // Apply some default constraints to ScrollView & its bound actors
+  // Movement + Wrap function
+
+  Constraint constraint;
+
+  // MoveActor (scrolling)
+  constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, MoveActorConstraint);
+  constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::SCROLL_POSITION));
+  constraint.SetRemoveAction(Constraint::DISCARD);
+  scrollView.ApplyConstraintToBoundActors(constraint);
+
+  // WrapActor (wrap functionality)
+  constraint = Constraint::New<Vector3>(scrollViewActor, Actor::Property::POSITION, WrapActorConstraint);
+  constraint.AddSource(LocalSource(Actor::Property::SCALE));
+  constraint.AddSource(LocalSource(Actor::Property::ANCHOR_POINT));
+  constraint.AddSource(LocalSource(Actor::Property::SIZE));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
+  constraint.AddSource(Source(scrollViewActor, Toolkit::ScrollView::Property::WRAP));
+  constraint.SetRemoveAction(Constraint::DISCARD);
+  scrollView.ApplyConstraintToBoundActors(constraint);
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h
new file mode 100644 (file)
index 0000000..540a3fd
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class ScrollView;
+
+/// Sets up and owns the Constraints used by the ScrollView class
+class ScrollViewConstraints
+{
+public:
+
+  ScrollViewConstraints() = default;  ///< Default Constructor
+  ~ScrollViewConstraints() = default; ///< Default Non-Virtual Destructor
+
+  // Not copyable or moveable
+  ScrollViewConstraints(const ScrollViewConstraints&) = delete;
+  ScrollViewConstraints(ScrollViewConstraints&&) = delete;
+  ScrollViewConstraints& operator=(const ScrollViewConstraints&) = delete;
+  ScrollViewConstraints& operator=(ScrollViewConstraints&&) = delete;
+
+  /**
+   * Updates the main internal scroll constraints with new ruler and domain values
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   */
+  void UpdateMainInternalConstraint(Internal::ScrollView& scrollView);
+
+  /**
+   * Enables/disables the overshoot constraints
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   * @param[in] enabled whether to enable or disable the overshoot constraints
+   */
+  void SetOvershootConstraintsEnabled(ScrollView& scrollView, bool enabled);
+
+  /**
+   * Sets internal constraints for this ScrollView.
+   * Many of these internal constraints are based on properties within ScrollView.
+   *
+   * @param[in] scrollView A reference to the scroll view object
+   */
+  void SetInternalConstraints(ScrollView& scrollView);
+
+public:
+
+  Constraint mScrollMainInternalPrePositionConstraint;
+  Constraint mScrollMainInternalPositionConstraint;
+  Constraint mScrollMainInternalOvershootXConstraint;
+  Constraint mScrollMainInternalOvershootYConstraint;
+  Constraint mScrollMainInternalDeltaConstraint;
+  Constraint mScrollMainInternalFinalConstraint;
+  Constraint mScrollMainInternalRelativeConstraint;
+  Constraint mScrollMainInternalDomainConstraint;
+  Constraint mScrollMainInternalPrePositionMaxConstraint;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_CONSTRAINTS_H
index 8ca6855..86cfc56 100644 (file)
@@ -43,7 +43,7 @@
 //#define ENABLED_SCROLL_STATE_LOGGING
 
 #ifdef ENABLED_SCROLL_STATE_LOGGING
-#define DALI_LOG_SCROLL_STATE(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, "%s:%d " format "\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define DALI_LOG_SCROLL_STATE(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DebugInfo, "%s:%d " format "\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 #else
 #define DALI_LOG_SCROLL_STATE(format, ...)
 #endif
 // TODO: Orientation.
 // TODO: upgrade Vector2/3 to support returning Unit vectors, normals, & cross product (dot product is already provided)
 
-using namespace Dali;
-
 namespace
 {
-const float DEFAULT_SLOW_SNAP_ANIMATION_DURATION(0.5f);  ///< Default Drag-Release animation time.
-const float DEFAULT_FAST_SNAP_ANIMATION_DURATION(0.25f); ///< Default Drag-Flick animation time.
-const float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);       ///< Default Overshoot snapping animation time.
-const float DEFAULT_MAX_OVERSHOOT(100.0f);               ///< Default maximum allowed overshoot in pixels
-
-const float DEFAULT_AXIS_AUTO_LOCK_GRADIENT(0.36f); ///< Default Axis-AutoLock gradient threshold. default is 0.36:1 (20 degrees)
-const float DEFAULT_FRICTION_COEFFICIENT(1.0f);     ///< Default Friction Co-efficient. (in stage diagonals per second)
-const float DEFAULT_FLICK_SPEED_COEFFICIENT(1.0f);  ///< Default Flick speed coefficient (multiples input touch velocity)
-const float DEFAULT_MAX_FLICK_SPEED(3.0f);          ///< Default Maximum flick speed. (in stage diagonals per second)
-
-const Vector2       DEFAULT_MIN_FLICK_DISTANCE(30.0f, 30.0f);                             ///< minimum distance for pan before flick allowed
-const float         DEFAULT_MIN_FLICK_SPEED_THRESHOLD(500.0f);                            ///< Minimum pan speed required for flick in pixels/s
-const float         FREE_FLICK_SPEED_THRESHOLD                    = 200.0f;               ///< Free-Flick threshold in pixels/ms
-const float         AUTOLOCK_AXIS_MINIMUM_DISTANCE2               = 100.0f;               ///< Auto-lock axis after minimum distance squared.
-const float         FLICK_ORTHO_ANGLE_RANGE                       = 75.0f;                ///< degrees. (if >45, then supports diagonal flicking)
-const Vector2       DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each wheel event received.
-const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET(150u);
-const float         TOUCH_DOWN_TIMER_INTERVAL = 100.0f;
-const float         DEFAULT_SCROLL_UPDATE_DISTANCE(30.0f); ///< Default distance to travel in pixels for scroll update signal
+using namespace Dali;
+
+constexpr float DEFAULT_SLOW_SNAP_ANIMATION_DURATION(0.5f);  ///< Default Drag-Release animation time.
+constexpr float DEFAULT_FAST_SNAP_ANIMATION_DURATION(0.25f); ///< Default Drag-Flick animation time.
+constexpr float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);       ///< Default Overshoot snapping animation time.
+constexpr float DEFAULT_MAX_OVERSHOOT(100.0f);               ///< Default maximum allowed overshoot in pixels
+
+constexpr float DEFAULT_AXIS_AUTO_LOCK_GRADIENT(0.36f); ///< Default Axis-AutoLock gradient threshold. default is 0.36:1 (20 degrees)
+constexpr float DEFAULT_FRICTION_COEFFICIENT(1.0f);     ///< Default Friction Co-efficient. (in stage diagonals per second)
+constexpr float DEFAULT_FLICK_SPEED_COEFFICIENT(1.0f);  ///< Default Flick speed coefficient (multiples input touch velocity)
+constexpr float DEFAULT_MAX_FLICK_SPEED(3.0f);          ///< Default Maximum flick speed. (in stage diagonals per second)
+
+constexpr Dali::Vector2 DEFAULT_MIN_FLICK_DISTANCE(30.0f, 30.0f);  ///< minimum distance for pan before flick allowed
+constexpr float         DEFAULT_MIN_FLICK_SPEED_THRESHOLD(500.0f); ///< Minimum pan speed required for flick in pixels/s
+
+constexpr float FREE_FLICK_SPEED_THRESHOLD      = 200.0f; ///< Free-Flick threshold in pixels/ms
+constexpr float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f; ///< Auto-lock axis after minimum distance squared.
+constexpr float FLICK_ORTHO_ANGLE_RANGE         = 75.0f;  ///< degrees. (if >45, then supports diagonal flicking)
+
+constexpr Dali::Vector2 DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each wheel event received.
+
+constexpr unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET(150u);
+constexpr float         TOUCH_DOWN_TIMER_INTERVAL = 100.0f;
+constexpr float         DEFAULT_SCROLL_UPDATE_DISTANCE(30.0f); ///< Default distance to travel in pixels for scroll update signal
 
 const std::string INTERNAL_MAX_POSITION_PROPERTY_NAME("internalMaxPosition");
 
@@ -104,7 +107,7 @@ float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::Di
 {
   if(bias == Dali::Toolkit::DIRECTION_BIAS_NONE)
   {
-    return ShortestDistanceInDomain(a, b, start, end);
+    return Dali::ShortestDistanceInDomain(a, b, start, end);
   }
   //  (a-start + end-b)
   float size = end - start;
@@ -145,22 +148,118 @@ float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::Di
  * @param anchor The Anchor point of interest.
  * @return The position of the Anchor
  */
-Vector3 GetPositionOfAnchor(Actor& actor, const Vector3& anchor)
+Dali::Vector3 GetPositionOfAnchor(Dali::Actor& actor, const Dali::Vector3& anchor)
 {
-  Vector3 childPosition = actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
-  Vector3 childAnchor   = -actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) + anchor;
-  Vector3 childSize     = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+  Dali::Vector3 childPosition = actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::POSITION);
+  Dali::Vector3 childAnchor   = -actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::ANCHOR_POINT) + anchor;
+  Dali::Vector3 childSize     = actor.GetCurrentProperty<Dali::Vector3>(Dali::Actor::Property::SIZE);
 
   return childPosition + childAnchor * childSize;
 }
 
-// AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the closest actor to the given position
+ * @param[in] actor The scrollview actor
+ * @param[in] internalActor The internal actor (to ignore)
+ * @param[in] position The given position
+ * @param[in] dirX Direction to search in
+ * @param[in] dirY Direction to search in
+ * @param[in] dirZ Direction to search in
+ * @return the closest child actor
+ */
+using FindDirection = Dali::Toolkit::Internal::ScrollView::FindDirection;
 
-float FinalDefaultAlphaFunction(float offset)
+Actor FindClosestActorToPosition(
+  CustomActor actor, Actor internalActor, const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
 {
-  return offset * 0.5f;
+  Actor   closestChild;
+  float   closestDistance2 = 0.0f;
+  Vector3 actualPosition   = position;
+
+  unsigned int numChildren = actor.GetChildCount();
+
+  for(unsigned int i = 0; i < numChildren; ++i)
+  {
+    Actor child = actor.GetChildAt(i);
+
+    if(internalActor == child) // ignore internal actor.
+    {
+      continue;
+    }
+
+    Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
+
+    Vector3 delta = childPosition - actualPosition;
+
+    // X-axis checking (only find Actors to the [dirX] of actualPosition)
+    if(dirX > FindDirection::All) // != All,None
+    {
+      FindDirection deltaH = delta.x > 0 ? FindDirection::Right : FindDirection::Left;
+      if(dirX != deltaH)
+      {
+        continue;
+      }
+    }
+
+    // Y-axis checking (only find Actors to the [dirY] of actualPosition)
+    if(dirY > FindDirection::All) // != All,None
+    {
+      FindDirection deltaV = delta.y > 0 ? FindDirection::Down : FindDirection::Up;
+      if(dirY != deltaV)
+      {
+        continue;
+      }
+    }
+
+    // Z-axis checking (only find Actors to the [dirZ] of actualPosition)
+    if(dirZ > FindDirection::All) // != All,None
+    {
+      FindDirection deltaV = delta.y > 0 ? FindDirection::In : FindDirection::Out;
+      if(dirZ != deltaV)
+      {
+        continue;
+      }
+    }
+
+    // compare child to closest child in terms of distance.
+    float distance2 = 0.0f;
+
+    // distance2 = the Square of the relevant dimensions of delta
+    if(dirX != FindDirection::None)
+    {
+      distance2 += delta.x * delta.x;
+    }
+
+    if(dirY != FindDirection::None)
+    {
+      distance2 += delta.y * delta.y;
+    }
+
+    if(dirZ != FindDirection::None)
+    {
+      distance2 += delta.z * delta.z;
+    }
+
+    if(closestChild) // Next time.
+    {
+      if(distance2 < closestDistance2)
+      {
+        closestChild     = child;
+        closestDistance2 = distance2;
+      }
+    }
+    else // First time.
+    {
+      closestChild     = child;
+      closestDistance2 = distance2;
+    }
+  }
+
+  return closestChild;
 }
 
+// AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
+
 /**
  * ConstantDecelerationAlphaFunction
  * Newtoninan distance for constant deceleration
@@ -177,54 +276,257 @@ float ConstantDecelerationAlphaFunction(float progress)
   return progress * 2.0f - progress * progress;
 }
 
-// Internal Constraints ///////////////////////////////////////////////////////////////////////////
-
 /**
- * Internal Relative position Constraint
- * Generates the relative position value of the scroll view
- * based on the absolute position, and it's relation to the
- * scroll domain. This is a value from 0.0f to 1.0f in each
- * scroll position axis.
+ * Clamp a position
+ * @param[in] size The size to clamp to
+ * @param[in] rulerX The horizontal ruler
+ * @param[in] rulerY The vertical ruler
+ * @param[in,out] position The position to clamp
+ * @param[out] clamped the clamped state
  */
-void InternalRelativePositionConstraint(Vector2& relativePosition, const PropertyInputContainer& inputs)
+void ClampPosition(const Vector3& size, Dali::Toolkit::RulerPtr rulerX, Dali::Toolkit::RulerPtr rulerY, Vector2& position, Dali::Toolkit::ClampState2D& clamped)
 {
-  Vector2        position = -inputs[0]->GetVector2();
-  const Vector2& min      = inputs[1]->GetVector2();
-  const Vector2& max      = inputs[2]->GetVector2();
-  const Vector3& size     = inputs[3]->GetVector3();
-
-  position.x = WrapInDomain(position.x, min.x, max.x);
-  position.y = WrapInDomain(position.y, min.y, max.y);
-
-  Vector2 domainSize = (max - min) - size.GetVectorXY();
-
-  relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
-  relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
+  position.x = -rulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);  // NOTE: X & Y rulers think in -ve coordinate system.
+  position.y = -rulerY->Clamp(-position.y, size.height, 1.0f, clamped.y); // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
 }
 
 /**
- * Internal scroll domain Constraint
- * Generates the scroll domain of the scroll view.
+ * TODO: In situations where axes are different (X snap, Y free)
+ * Each axis should really have their own independent animation (time and equation)
+ * Consider, X axis snapping to nearest grid point (EaseOut over fixed time)
+ * Consider, Y axis simulating physics to arrive at a point (Physics equation over variable time)
+ * Currently, the axes have been split however, they both use the same EaseOut equation.
+ *
+ * @param[in] scrollView The main scrollview
+ * @param[in] rulerX The X ruler
+ * @param[in] rulerY The Y ruler
+ * @param[in] lockAxis Which axis (if any) is locked.
+ * @param[in] velocity Current pan velocity
+ * @param[in] maxOvershoot Maximum overshoot
+ * @param[in] inAcessibilityPan True if we are currently panning with accessibility
+ * @param[out] positionSnap The target position of snap animation
+ * @param[out] positionDuration The duration of the snap animation
+ * @param[out] alphaFunction The snap animation alpha function
+ * @param[out] isFlick if we are flicking or not
+ * @param[out] isFreeFlick if we are free flicking or not
  */
-void InternalScrollDomainConstraint(Vector2& scrollDomain, const PropertyInputContainer& inputs)
+void SnapWithVelocity(
+  Dali::Toolkit::Internal::ScrollView&          scrollView,
+  Dali::Toolkit::RulerPtr                       rulerX,
+  Dali::Toolkit::RulerPtr                       rulerY,
+  Dali::Toolkit::Internal::ScrollView::LockAxis lockAxis,
+  Vector2                                       velocity,
+  Vector2                                       maxOvershoot,
+  Vector2&                                      positionSnap,
+  Vector2&                                      positionDuration,
+  AlphaFunction&                                alphaFunction,
+  bool                                          inAccessibilityPan,
+  bool&                                         isFlick,
+  bool&                                         isFreeFlick)
 {
-  const Vector2& min  = inputs[0]->GetVector2();
-  const Vector2& max  = inputs[1]->GetVector2();
-  const Vector3& size = inputs[2]->GetVector3();
+  // Animator takes over now, touches are assumed not to interfere.
+  // And if touches do interfere, then we'll stop animation, update PrePosition
+  // to current mScroll's properties, and then resume.
+  // Note: For Flicking this may work a bit different...
 
-  scrollDomain = (max - min) - size.GetVectorXY();
-}
+  float         angle      = atan2(velocity.y, velocity.x);
+  float         speed2     = velocity.LengthSquared();
+  float         biasX      = 0.5f;
+  float         biasY      = 0.5f;
+  FindDirection horizontal = FindDirection::None;
+  FindDirection vertical   = FindDirection::None;
 
-/**
- * Internal maximum scroll position Constraint
- * Generates the maximum scroll position of the scroll view.
- */
-void InternalPrePositionMaxConstraint(Vector2& scrollMax, const PropertyInputContainer& inputs)
-{
-  const Vector2& max  = inputs[0]->GetVector2();
-  const Vector3& size = inputs[1]->GetVector3();
+  using LockAxis = Dali::Toolkit::Internal::ScrollView::LockAxis;
+
+  // orthoAngleRange = Angle tolerance within the Exact N,E,S,W direction
+  // that will be accepted as a general N,E,S,W flick direction.
+
+  const float orthoAngleRange      = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f;
+  const float flickSpeedThreshold2 = scrollView.GetMinimumSpeedForFlick() * scrollView.GetMinimumSpeedForFlick();
+
+  // Flick logic X Axis
+
+  if(rulerX->IsEnabled() && lockAxis != LockAxis::LockHorizontal)
+  {
+    horizontal = FindDirection::All;
+
+    if(speed2 > flickSpeedThreshold2 || // exceeds flick threshold
+       inAccessibilityPan)              // With AccessibilityPan its easier to move between snap positions
+    {
+      if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
+      {
+        biasX = 0.0f, horizontal = FindDirection::Left;
+
+        // This guards against an error where no movement occurs, due to the flick finishing
+        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
+        positionSnap.x += 1.0f;
+      }
+      else if((angle >= M_PI - orthoAngleRange) || (angle < -M_PI + orthoAngleRange)) // Swiping West
+      {
+        biasX = 1.0f, horizontal = FindDirection::Right;
+
+        // This guards against an error where no movement occurs, due to the flick finishing
+        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
+        positionSnap.x -= 1.0f;
+      }
+    }
+  }
+
+  // Flick logic Y Axis
+
+  if(rulerY->IsEnabled() && lockAxis != LockAxis::LockVertical)
+  {
+    vertical = FindDirection::All;
+
+    if(speed2 > flickSpeedThreshold2 || // exceeds flick threshold
+       inAccessibilityPan)              // With AccessibilityPan its easier to move between snap positions
+    {
+      if((angle >= M_PI_2 - orthoAngleRange) && (angle < M_PI_2 + orthoAngleRange)) // Swiping South
+      {
+        biasY = 0.0f, vertical = FindDirection::Up;
+      }
+      else if((angle >= -M_PI_2 - orthoAngleRange) && (angle < -M_PI_2 + orthoAngleRange)) // Swiping North
+      {
+        biasY = 1.0f, vertical = FindDirection::Down;
+      }
+    }
+  }
+
+  // isFlick: Whether this gesture is a flick or not.
+  isFlick = (horizontal != FindDirection::All || vertical != FindDirection::All);
+  // isFreeFlick: Whether this gesture is a flick under free panning criteria.
+  isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD * FREE_FLICK_SPEED_THRESHOLD);
+
+  if(isFlick || isFreeFlick)
+  {
+    positionDuration = Vector2::ONE * scrollView.GetScrollFlickDuration();
+    alphaFunction    = scrollView.GetScrollFlickAlphaFunction();
+  }
+
+  // Calculate next positionSnap ////////////////////////////////////////////////////////////
+
+  if(scrollView.GetActorAutoSnap())
+  {
+    Vector3 size = scrollView.Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+
+    Actor child = scrollView.FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f), horizontal, vertical);
+
+    if(!child && isFlick)
+    {
+      // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
+      child = scrollView.FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f));
+    }
+
+    if(child)
+    {
+      Vector2 position = scrollView.Self().GetCurrentProperty<Vector2>(Toolkit::ScrollView::Property::SCROLL_POSITION);
+
+      // Get center-point of the Actor.
+      Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
+
+      if(rulerX->IsEnabled())
+      {
+        positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
+      }
+      if(rulerY->IsEnabled())
+      {
+        positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
+      }
+    }
+  }
+
+  Vector2 startPosition = positionSnap;
+  positionSnap.x        = -rulerX->Snap(-positionSnap.x, biasX); // NOTE: X & Y rulers think in -ve coordinate system.
+  positionSnap.y        = -rulerY->Snap(-positionSnap.y, biasY); // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
+
+  Dali::Toolkit::ClampState2D clamped;
+  Vector3                     size = scrollView.Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+  Vector2                     clampDelta(Vector2::ZERO);
+  ClampPosition(size, rulerX, rulerY, positionSnap, clamped);
+
+  if((rulerX->GetType() == Dali::Toolkit::Ruler::FREE || rulerY->GetType() == Dali::Toolkit::Ruler::FREE) &&
+     isFreeFlick && !scrollView.GetActorAutoSnap())
+  {
+    // Calculate target position based on velocity of flick.
+
+    // a = Deceleration (Set to diagonal stage length * friction coefficient)
+    // u = Initial Velocity (Flick velocity)
+    // v = 0 (Final Velocity)
+    // t = Time (Velocity / Deceleration)
+    Vector2 stageSize   = Stage::GetCurrent().GetSize();
+    float   stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
+    float   a           = (stageLength * scrollView.GetFrictionCoefficient());
+    Vector3 u           = Vector3(velocity.x, velocity.y, 0.0f) * scrollView.GetFlickSpeedCoefficient();
+    float   speed       = u.Length();
+    u /= speed;
+
+    // TODO: Change this to a decay function. (faster you flick, the slower it should be)
+    speed = std::min(speed, stageLength * scrollView.GetMaxFlickSpeed());
+    u *= speed;
+    alphaFunction = ConstantDecelerationAlphaFunction;
+
+    float t = speed / a;
+
+    if(rulerX->IsEnabled() && rulerX->GetType() == Dali::Toolkit::Ruler::FREE)
+    {
+      positionSnap.x += t * u.x * 0.5f;
+    }
+
+    if(rulerY->IsEnabled() && rulerY->GetType() == Dali::Toolkit::Ruler::FREE)
+    {
+      positionSnap.y += t * u.y * 0.5f;
+    }
+
+    clampDelta = positionSnap;
+    ClampPosition(size, rulerX, rulerY, positionSnap, clamped);
+
+    if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
+    {
+      clampDelta -= positionSnap;
+      clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, maxOvershoot.x) : std::max(clampDelta.x, -maxOvershoot.x);
+      clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, maxOvershoot.y) : std::max(clampDelta.y, -maxOvershoot.y);
+    }
+    else
+    {
+      clampDelta = Vector2::ZERO;
+    }
+
+    // If Axis is Free and has velocity, then calculate time taken
+    // to reach target based on velocity in axis.
+    if(rulerX->IsEnabled() && rulerX->GetType() == Dali::Toolkit::Ruler::FREE)
+    {
+      float deltaX = fabsf(startPosition.x - positionSnap.x);
+
+      if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
+      {
+        positionDuration.x = fabsf(deltaX / u.x);
+      }
+      else
+      {
+        positionDuration.x = 0;
+      }
+    }
+
+    if(rulerY->IsEnabled() && rulerY->GetType() == Dali::Toolkit::Ruler::FREE)
+    {
+      float deltaY = fabsf(startPosition.y - positionSnap.y);
+
+      if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
+      {
+        positionDuration.y = fabsf(deltaY / u.y);
+      }
+      else
+      {
+        positionDuration.y = 0;
+      }
+    }
+  }
 
-  scrollMax = max - size.GetVectorXY();
+  if(scrollView.IsOvershootEnabled())
+  {
+    // Scroll to the end of the overshoot only when overshoot is enabled.
+    positionSnap += clampDelta;
+  }
 }
 
 } // unnamed namespace
@@ -277,336 +579,6 @@ DALI_SIGNAL_REGISTRATION(Toolkit, ScrollView, "valueChanged", SIGNAL_SNAP_STARTE
 
 DALI_TYPE_REGISTRATION_END()
 
-/**
- * Returns whether to lock scrolling to a particular axis
- *
- * @param[in] panDelta Distance panned since gesture started
- * @param[in] currentLockAxis The current lock axis value
- * @param[in] lockGradient How quickly to lock to a particular axis
- *
- * @return The new axis lock state
- */
-ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
-{
-  if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
-     currentLockAxis == ScrollView::LockPossible)
-  {
-    float dx = fabsf(panDelta.x);
-    float dy = fabsf(panDelta.y);
-    if(dx * lockGradient >= dy)
-    {
-      // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
-      currentLockAxis = ScrollView::LockVertical;
-    }
-    else if(dy * lockGradient > dx)
-    {
-      // 0.36:1 gradient to the vertical (deviate < 20 degrees)
-      currentLockAxis = ScrollView::LockHorizontal;
-    }
-    else
-    {
-      currentLockAxis = ScrollView::LockNone;
-    }
-  }
-  return currentLockAxis;
-}
-
-/**
- * Internal Pre-Position Property Constraint.
- *
- * Generates position property based on current position + gesture displacement.
- * Or generates position property based on positionX/Y.
- * Note: This is the position prior to any clamping at scroll boundaries.
- */
-struct InternalPrePositionConstraint
-{
-  InternalPrePositionConstraint(const Vector2&       initialPanPosition,
-                                const Vector2&       initialPanMask,
-                                bool                 axisAutoLock,
-                                float                axisAutoLockGradient,
-                                ScrollView::LockAxis initialLockAxis,
-                                const Vector2&       maxOvershoot,
-                                const RulerPtr&      rulerX,
-                                const RulerPtr&      rulerY)
-  : mLocalStart(initialPanPosition),
-    mInitialPanMask(initialPanMask),
-    mMaxOvershoot(maxOvershoot),
-    mAxisAutoLockGradient(axisAutoLockGradient),
-    mLockAxis(initialLockAxis),
-    mAxisAutoLock(axisAutoLock),
-    mWasPanning(false)
-  {
-    const RulerDomain& rulerDomainX = rulerX->GetDomain();
-    const RulerDomain& rulerDomainY = rulerY->GetDomain();
-    mDomainMin                      = Vector2(rulerDomainX.min, -rulerDomainY.min);
-    mDomainMax                      = Vector2(-rulerDomainX.max, -rulerDomainY.max);
-    mClampX                         = rulerDomainX.enabled;
-    mClampY                         = rulerDomainY.enabled;
-    mFixedRulerX                    = rulerX->GetType() == Ruler::FIXED;
-    mFixedRulerY                    = rulerY->GetType() == Ruler::FIXED;
-  }
-
-  void operator()(Vector2& scrollPostPosition, const PropertyInputContainer& inputs)
-  {
-    const Vector2& panPosition = inputs[0]->GetVector2();
-    const bool&    inGesture   = inputs[1]->GetBoolean();
-
-    // First check if we are within a gesture.
-    // The ScrollView may have received a start gesture from ::OnPan()
-    // while the finish gesture is received now in this constraint.
-    // This gesture must then be rejected as the value will be "old".
-    // Typically the last value from the end of the last gesture.
-    // If we are rejecting the gesture, we simply don't modify the constraint target.
-    if(inGesture)
-    {
-      if(!mWasPanning)
-      {
-        mPrePosition    = scrollPostPosition;
-        mStartPosition  = mPrePosition;
-        mCurrentPanMask = mInitialPanMask;
-        mWasPanning     = true;
-      }
-
-      // Calculate Deltas...
-      const Vector2& currentPosition = panPosition;
-      Vector2        panDelta(currentPosition - mLocalStart);
-
-      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
-      // appears mostly horizontal or mostly vertical respectively...
-      if(mAxisAutoLock)
-      {
-        mLockAxis = GetLockAxis(panDelta, mLockAxis, mAxisAutoLockGradient);
-        if(mLockAxis == ScrollView::LockVertical)
-        {
-          mCurrentPanMask.y = 0.0f;
-        }
-        else if(mLockAxis == ScrollView::LockHorizontal)
-        {
-          mCurrentPanMask.x = 0.0f;
-        }
-      }
-
-      // Restrict deltas based on ruler enable/disable and axis-lock state...
-      panDelta *= mCurrentPanMask;
-
-      // Perform Position transform based on input deltas...
-      scrollPostPosition = mPrePosition;
-      scrollPostPosition += panDelta;
-
-      // if no wrapping then clamp preposition to maximum overshoot amount
-      const Vector3& size = inputs[2]->GetVector3();
-      if(mClampX)
-      {
-        float newXPosition = Clamp(scrollPostPosition.x, (mDomainMax.x + size.x) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x);
-        if((newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1) || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1))
-        {
-          mPrePosition.x = newXPosition;
-          mLocalStart.x  = panPosition.x;
-        }
-        scrollPostPosition.x = newXPosition;
-      }
-      if(mClampY)
-      {
-        float newYPosition = Clamp(scrollPostPosition.y, (mDomainMax.y + size.y) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y);
-        if((newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1) || (newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1))
-        {
-          mPrePosition.y = newYPosition;
-          mLocalStart.y  = panPosition.y;
-        }
-        scrollPostPosition.y = newYPosition;
-      }
-
-      // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
-      if(mFixedRulerX || mFixedRulerY)
-      {
-        // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
-        // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
-        // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
-        // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
-        //       When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
-        //       A flick finishes before the update thread has advanced the scroll position past the previous snap point.
-        Vector2 viewPageSizeLimit(size.x - (1.0f + 1.0f), size.y - (1.0f - 1.0f));
-        Vector2 minPosition(mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y);
-        Vector2 maxPosition(mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.y);
-
-        if(mFixedRulerX)
-        {
-          scrollPostPosition.x = Clamp(scrollPostPosition.x, minPosition.x, maxPosition.x);
-        }
-        if(mFixedRulerY)
-        {
-          scrollPostPosition.y = Clamp(scrollPostPosition.y, minPosition.y, maxPosition.y);
-        }
-      }
-    }
-  }
-
-  Vector2 mPrePosition;
-  Vector2 mLocalStart;
-  Vector2 mStartPosition;  ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
-  Vector2 mInitialPanMask; ///< Initial pan mask (based on ruler settings).
-  Vector2 mCurrentPanMask; ///< Current pan mask that can be altered by axis lock mode.
-  Vector2 mDomainMin;
-  Vector2 mDomainMax;
-  Vector2 mMaxOvershoot;
-
-  float                mAxisAutoLockGradient; ///< Set by ScrollView
-  ScrollView::LockAxis mLockAxis;
-
-  bool mAxisAutoLock : 1; ///< Set by ScrollView
-  bool mWasPanning : 1;
-  bool mClampX : 1;
-  bool mClampY : 1;
-  bool mFixedRulerX : 1;
-  bool mFixedRulerY : 1;
-};
-
-/**
- * Internal Position Property Constraint.
- *
- * Generates position property based on pre-position
- * Note: This is the position after clamping.
- * (uses result of InternalPrePositionConstraint)
- */
-struct InternalPositionConstraint
-{
-  InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
-  : mDomainMin(-domainX.min, -domainY.min),
-    mDomainMax(-domainX.max, -domainY.max),
-    mClampX(domainX.enabled),
-    mClampY(domainY.enabled),
-    mWrap(wrap)
-  {
-  }
-
-  void operator()(Vector2& position, const PropertyInputContainer& inputs)
-  {
-    position            = inputs[0]->GetVector2();
-    const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
-    const Vector2& min  = inputs[1]->GetVector2();
-    const Vector2& max  = inputs[2]->GetVector2();
-
-    if(mWrap)
-    {
-      position.x = -WrapInDomain(-position.x, min.x, max.x);
-      position.y = -WrapInDomain(-position.y, min.y, max.y);
-    }
-    else
-    {
-      // clamp post position to domain
-      position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x) : position.x;
-      position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y) : position.y;
-    }
-  }
-
-  Vector2 mDomainMin;
-  Vector2 mDomainMax;
-  bool    mClampX;
-  bool    mClampY;
-  bool    mWrap;
-};
-
-/**
- * This constraint updates the X overshoot property using the difference
- * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
- */
-struct OvershootXConstraint
-{
-  OvershootXConstraint(float maxOvershoot)
-  : mMaxOvershoot(maxOvershoot)
-  {
-  }
-
-  void operator()(float& current, const PropertyInputContainer& inputs)
-  {
-    if(inputs[2]->GetBoolean())
-    {
-      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
-      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
-      float          newOvershoot       = scrollPrePosition.x - scrollPostPosition.x;
-      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
-    }
-    else
-    {
-      current = 0.0f;
-    }
-  }
-
-  float mMaxOvershoot;
-};
-
-/**
- * This constraint updates the Y overshoot property using the difference
- * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
- */
-struct OvershootYConstraint
-{
-  OvershootYConstraint(float maxOvershoot)
-  : mMaxOvershoot(maxOvershoot)
-  {
-  }
-
-  void operator()(float& current, const PropertyInputContainer& inputs)
-  {
-    if(inputs[2]->GetBoolean())
-    {
-      const Vector2& scrollPrePosition  = inputs[0]->GetVector2();
-      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
-      float          newOvershoot       = scrollPrePosition.y - scrollPostPosition.y;
-      current                           = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
-    }
-    else
-    {
-      current = 0.0f;
-    }
-  }
-
-  float mMaxOvershoot;
-};
-
-/**
- * Internal Position-Delta Property Constraint.
- *
- * Generates position-delta property based on scroll-position + scroll-offset properties.
- */
-void InternalPositionDeltaConstraint(Vector2& current, const PropertyInputContainer& inputs)
-{
-  const Vector2& scrollPosition = inputs[0]->GetVector2();
-  const Vector2& scrollOffset   = inputs[1]->GetVector2();
-
-  current = scrollPosition + scrollOffset;
-}
-
-/**
- * Internal Final Position Constraint
- * The position of content is:
- * of scroll-position + f(scroll-overshoot)
- * where f(...) function defines how overshoot
- * should affect final-position.
- */
-struct InternalFinalConstraint
-{
-  InternalFinalConstraint(AlphaFunctionPrototype functionX,
-                          AlphaFunctionPrototype functionY)
-  : mFunctionX(functionX),
-    mFunctionY(functionY)
-  {
-  }
-
-  void operator()(Vector2& current, const PropertyInputContainer& inputs)
-  {
-    const float& overshootx = inputs[1]->GetFloat();
-    const float& overshooty = inputs[2]->GetFloat();
-    Vector2      offset(mFunctionX(overshootx),
-                   mFunctionY(overshooty));
-
-    current = inputs[0]->GetVector2() - offset;
-  }
-
-  AlphaFunctionPrototype mFunctionX;
-  AlphaFunctionPrototype mFunctionY;
-};
-
 } // namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -702,7 +674,7 @@ void ScrollView::OnInitialize()
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal);
 
   UpdatePropertyDomain();
-  SetInternalConstraints();
+  mConstraints.SetInternalConstraints(*this);
 
   // Connect wheel event
   self.WheelEventSignal().Connect(this, &ScrollView::OnWheelEvent);
@@ -746,46 +718,6 @@ ScrollView::~ScrollView()
   DALI_LOG_SCROLL_STATE("[0x%X]", this);
 }
 
-AlphaFunction ScrollView::GetScrollSnapAlphaFunction() const
-{
-  return mSnapAlphaFunction;
-}
-
-void ScrollView::SetScrollSnapAlphaFunction(AlphaFunction alpha)
-{
-  mSnapAlphaFunction = alpha;
-}
-
-AlphaFunction ScrollView::GetScrollFlickAlphaFunction() const
-{
-  return mFlickAlphaFunction;
-}
-
-void ScrollView::SetScrollFlickAlphaFunction(AlphaFunction alpha)
-{
-  mFlickAlphaFunction = alpha;
-}
-
-float ScrollView::GetScrollSnapDuration() const
-{
-  return mSnapDuration;
-}
-
-void ScrollView::SetScrollSnapDuration(float time)
-{
-  mSnapDuration = time;
-}
-
-float ScrollView::GetScrollFlickDuration() const
-{
-  return mFlickDuration;
-}
-
-void ScrollView::SetScrollFlickDuration(float time)
-{
-  mFlickDuration = time;
-}
-
 void ScrollView::ApplyEffect(Toolkit::ScrollViewEffect effect)
 {
   Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
@@ -858,22 +790,12 @@ void ScrollView::RemoveConstraintsFromChildren()
   RemoveConstraintsFromBoundActors();
 }
 
-const RulerPtr ScrollView::GetRulerX() const
-{
-  return mRulerX;
-}
-
-const RulerPtr ScrollView::GetRulerY() const
-{
-  return mRulerY;
-}
-
 void ScrollView::SetRulerX(RulerPtr ruler)
 {
   mRulerX = ruler;
 
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::SetRulerY(RulerPtr ruler)
@@ -881,7 +803,7 @@ void ScrollView::SetRulerY(RulerPtr ruler)
   mRulerY = ruler;
 
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::UpdatePropertyDomain()
@@ -981,11 +903,6 @@ void ScrollView::UpdatePropertyDomain()
   }
 }
 
-bool ScrollView::GetScrollSensitive()
-{
-  return mSensitive;
-}
-
 void ScrollView::SetScrollSensitive(bool sensitive)
 {
   Actor              self = Self();
@@ -1023,22 +940,7 @@ void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
   mMaxOvershoot.y      = overshootY;
   mUserMaxOvershoot    = mMaxOvershoot;
   mDefaultMaxOvershoot = false;
-  UpdateMainInternalConstraint();
-}
-
-void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
-{
-  mSnapOvershootAlphaFunction = alpha;
-}
-
-float ScrollView::GetSnapOvershootDuration()
-{
-  return mSnapOvershootDuration;
-}
-
-void ScrollView::SetSnapOvershootDuration(float duration)
-{
-  mSnapOvershootDuration = duration;
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 bool ScrollView::GetActorAutoSnap()
@@ -1046,64 +948,29 @@ bool ScrollView::GetActorAutoSnap()
   return mActorAutoSnapEnabled;
 }
 
-void ScrollView::SetActorAutoSnap(bool enable)
-{
-  mActorAutoSnapEnabled = enable;
-}
-
 void ScrollView::SetAutoResize(bool enable)
 {
   mAutoResizeContainerEnabled = enable;
   // TODO: This needs a lot of issues to be addressed before working.
 }
 
-bool ScrollView::GetWrapMode() const
-{
-  return mWrapMode;
-}
-
 void ScrollView::SetWrapMode(bool enable)
 {
   mWrapMode = enable;
   Self().SetProperty(Toolkit::ScrollView::Property::WRAP, enable);
 }
 
-int ScrollView::GetScrollUpdateDistance() const
-{
-  return mScrollUpdateDistance;
-}
-
-void ScrollView::SetScrollUpdateDistance(int distance)
-{
-  mScrollUpdateDistance = distance;
-}
-
-bool ScrollView::GetAxisAutoLock() const
-{
-  return mAxisAutoLock;
-}
-
 void ScrollView::SetAxisAutoLock(bool enable)
 {
   mAxisAutoLock = enable;
-  UpdateMainInternalConstraint();
-}
-
-float ScrollView::GetAxisAutoLockGradient() const
-{
-  return mAxisAutoLockGradient;
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::SetAxisAutoLockGradient(float gradient)
 {
   DALI_ASSERT_DEBUG(gradient >= 0.0f && gradient <= 1.0f);
   mAxisAutoLockGradient = gradient;
-  UpdateMainInternalConstraint();
-}
-
-float ScrollView::GetFrictionCoefficient() const
-{
-  return mFrictionCoefficient;
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::SetFrictionCoefficient(float friction)
@@ -1112,56 +979,6 @@ void ScrollView::SetFrictionCoefficient(float friction)
   mFrictionCoefficient = friction;
 }
 
-float ScrollView::GetFlickSpeedCoefficient() const
-{
-  return mFlickSpeedCoefficient;
-}
-
-void ScrollView::SetFlickSpeedCoefficient(float speed)
-{
-  mFlickSpeedCoefficient = speed;
-}
-
-Vector2 ScrollView::GetMinimumDistanceForFlick() const
-{
-  return mMinFlickDistance;
-}
-
-void ScrollView::SetMinimumDistanceForFlick(const Vector2& distance)
-{
-  mMinFlickDistance = distance;
-}
-
-float ScrollView::GetMinimumSpeedForFlick() const
-{
-  return mFlickSpeedThreshold;
-}
-
-void ScrollView::SetMinimumSpeedForFlick(float speed)
-{
-  mFlickSpeedThreshold = speed;
-}
-
-float ScrollView::GetMaxFlickSpeed() const
-{
-  return mMaxFlickSpeed;
-}
-
-void ScrollView::SetMaxFlickSpeed(float speed)
-{
-  mMaxFlickSpeed = speed;
-}
-
-void ScrollView::SetWheelScrollDistanceStep(Vector2 step)
-{
-  mWheelScrollDistanceStep = step;
-}
-
-Vector2 ScrollView::GetWheelScrollDistanceStep() const
-{
-  return mWheelScrollDistanceStep;
-}
-
 unsigned int ScrollView::GetCurrentPage() const
 {
   // in case animation is currently taking place.
@@ -1229,9 +1046,9 @@ void ScrollView::TransformTo(const Vector2& position, float duration, AlphaFunct
     mGestureStackDepth = 0;
     self.SetProperty(Toolkit::ScrollView::Property::PANNING, false);
 
-    if(mScrollMainInternalPrePositionConstraint)
+    if(mConstraints.mScrollMainInternalPrePositionConstraint)
     {
-      mScrollMainInternalPrePositionConstraint.Remove();
+      mConstraints.mScrollMainInternalPrePositionConstraint.Remove();
     }
   }
 
@@ -1244,408 +1061,126 @@ void ScrollView::TransformTo(const Vector2& position, float duration, AlphaFunct
                              Vector2::ONE * duration,
                              alpha,
                              true,
-                             horizontalBias,
-                             verticalBias,
-                             SNAP);
-
-  if(!animating)
-  {
-    // if not animating, then this pan has completed right now.
-    self.SetProperty(Toolkit::ScrollView::Property::SCROLLING, false);
-    mScrolling = false;
-
-    // If we have no duration, then in the next update frame, we will be at the position specified as we just set.
-    // In this scenario, we cannot return the currentScrollPosition as this is out-of-date and should instead return the requested final position
-    Vector2 completedPosition(currentScrollPosition);
-    if(duration <= Math::MACHINE_EPSILON_10)
-    {
-      completedPosition = position;
-    }
-
-    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 2 [%.2f, %.2f]", this, completedPosition.x, completedPosition.y);
-    SetScrollUpdateNotification(false);
-    mScrollCompletedSignal.Emit(completedPosition);
-  }
-}
-
-void ScrollView::ScrollTo(const Vector2& position)
-{
-  ScrollTo(position, mSnapDuration);
-}
-
-void ScrollView::ScrollTo(const Vector2& position, float duration)
-{
-  ScrollTo(position, duration, DIRECTION_BIAS_NONE, DIRECTION_BIAS_NONE);
-}
-
-void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha)
-{
-  ScrollTo(position, duration, alpha, DIRECTION_BIAS_NONE, DIRECTION_BIAS_NONE);
-}
-
-void ScrollView::ScrollTo(const Vector2& position, float duration, DirectionBias horizontalBias, DirectionBias verticalBias)
-{
-  ScrollTo(position, duration, mSnapAlphaFunction, horizontalBias, verticalBias);
-}
-
-void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha, DirectionBias horizontalBias, DirectionBias verticalBias)
-{
-  DALI_LOG_SCROLL_STATE("[0x%X] position[%.2f, %.2f] duration[%.2f], bias[%d, %d]", this, position.x, position.y, duration, int(horizontalBias), int(verticalBias));
-  TransformTo(position, duration, alpha, horizontalBias, verticalBias);
-}
-
-void ScrollView::ScrollTo(unsigned int page)
-{
-  ScrollTo(page, mSnapDuration);
-}
-
-void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
-{
-  Vector2      position;
-  unsigned int volume;
-  unsigned int libraries;
-
-  // The position to scroll to is continuous and linear
-  // unless a domain has been enabled on the X axis.
-  // or if WrapMode has been enabled.
-  bool carryX = mRulerX->GetDomain().enabled | mWrapMode;
-  bool carryY = mRulerY->GetDomain().enabled | mWrapMode;
-
-  position.x = mRulerX->GetPositionFromPage(page, volume, carryX);
-  position.y = mRulerY->GetPositionFromPage(volume, libraries, carryY);
-
-  ScrollTo(position, duration, bias, bias);
-}
-
-void ScrollView::ScrollTo(Actor& actor)
-{
-  ScrollTo(actor, mSnapDuration);
-}
-
-void ScrollView::ScrollTo(Actor& actor, float duration)
-{
-  DALI_ASSERT_ALWAYS(actor.GetParent() == Self());
-
-  Actor   self        = Self();
-  Vector3 size        = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
-  Vector3 position    = actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
-  Vector2 prePosition = GetPropertyPrePosition();
-  position.GetVectorXY() -= prePosition;
-
-  ScrollTo(Vector2(position.x - size.width * 0.5f, position.y - size.height * 0.5f), duration);
-}
-
-Actor ScrollView::FindClosestActor()
-{
-  Actor   self = Self();
-  Vector3 size = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
-
-  return FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f));
-}
-
-Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
-{
-  Actor   closestChild;
-  float   closestDistance2 = 0.0f;
-  Vector3 actualPosition   = position;
-
-  unsigned int numChildren = Self().GetChildCount();
-
-  for(unsigned int i = 0; i < numChildren; ++i)
-  {
-    Actor child = Self().GetChildAt(i);
-
-    if(mInternalActor == child) // ignore internal actor.
-    {
-      continue;
-    }
-
-    Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
-
-    Vector3 delta = childPosition - actualPosition;
-
-    // X-axis checking (only find Actors to the [dirX] of actualPosition)
-    if(dirX > All) // != All,None
-    {
-      FindDirection deltaH = delta.x > 0 ? Right : Left;
-      if(dirX != deltaH)
-      {
-        continue;
-      }
-    }
-
-    // Y-axis checking (only find Actors to the [dirY] of actualPosition)
-    if(dirY > All) // != All,None
-    {
-      FindDirection deltaV = delta.y > 0 ? Down : Up;
-      if(dirY != deltaV)
-      {
-        continue;
-      }
-    }
-
-    // Z-axis checking (only find Actors to the [dirZ] of actualPosition)
-    if(dirZ > All) // != All,None
-    {
-      FindDirection deltaV = delta.y > 0 ? In : Out;
-      if(dirZ != deltaV)
-      {
-        continue;
-      }
-    }
-
-    // compare child to closest child in terms of distance.
-    float distance2 = 0.0f;
-
-    // distance2 = the Square of the relevant dimensions of delta
-    if(dirX != None)
-    {
-      distance2 += delta.x * delta.x;
-    }
-
-    if(dirY != None)
-    {
-      distance2 += delta.y * delta.y;
-    }
-
-    if(dirZ != None)
-    {
-      distance2 += delta.z * delta.z;
-    }
-
-    if(closestChild) // Next time.
-    {
-      if(distance2 < closestDistance2)
-      {
-        closestChild     = child;
-        closestDistance2 = distance2;
-      }
-    }
-    else // First time.
-    {
-      closestChild     = child;
-      closestDistance2 = distance2;
-    }
-  }
-
-  return closestChild;
-}
-
-bool ScrollView::ScrollToSnapPoint()
-{
-  DALI_LOG_SCROLL_STATE("[0x%X]", this);
-  Vector2 stationaryVelocity = Vector2(0.0f, 0.0f);
-  return SnapWithVelocity(stationaryVelocity);
-}
-
-// TODO: In situations where axes are different (X snap, Y free)
-// Each axis should really have their own independent animation (time and equation)
-// Consider, X axis snapping to nearest grid point (EaseOut over fixed time)
-// Consider, Y axis simulating physics to arrive at a point (Physics equation over variable time)
-// Currently, the axes have been split however, they both use the same EaseOut equation.
-bool ScrollView::SnapWithVelocity(Vector2 velocity)
-{
-  // Animator takes over now, touches are assumed not to interfere.
-  // And if touches do interfere, then we'll stop animation, update PrePosition
-  // to current mScroll's properties, and then resume.
-  // Note: For Flicking this may work a bit different...
-
-  float         angle            = atan2(velocity.y, velocity.x);
-  float         speed2           = velocity.LengthSquared();
-  AlphaFunction alphaFunction    = mSnapAlphaFunction;
-  Vector2       positionDuration = Vector2::ONE * mSnapDuration;
-  float         biasX            = 0.5f;
-  float         biasY            = 0.5f;
-  FindDirection horizontal       = None;
-  FindDirection vertical         = None;
-
-  // orthoAngleRange = Angle tolerance within the Exact N,E,S,W direction
-  // that will be accepted as a general N,E,S,W flick direction.
-
-  const float orthoAngleRange      = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f;
-  const float flickSpeedThreshold2 = mFlickSpeedThreshold * mFlickSpeedThreshold;
-
-  Vector2 positionSnap = mScrollPrePosition;
-
-  // Flick logic X Axis
-
-  if(mRulerX->IsEnabled() && mLockAxis != LockHorizontal)
-  {
-    horizontal = All;
-
-    if(speed2 > flickSpeedThreshold2 || // exceeds flick threshold
-       mInAccessibilityPan)             // With AccessibilityPan its easier to move between snap positions
-    {
-      if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
-      {
-        biasX = 0.0f, horizontal = Left;
-
-        // This guards against an error where no movement occurs, due to the flick finishing
-        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
-        positionSnap.x += 1.0f;
-      }
-      else if((angle >= M_PI - orthoAngleRange) || (angle < -M_PI + orthoAngleRange)) // Swiping West
-      {
-        biasX = 1.0f, horizontal = Right;
-
-        // This guards against an error where no movement occurs, due to the flick finishing
-        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
-        positionSnap.x -= 1.0f;
-      }
-    }
-  }
-
-  // Flick logic Y Axis
+                             horizontalBias,
+                             verticalBias,
+                             SNAP);
 
-  if(mRulerY->IsEnabled() && mLockAxis != LockVertical)
+  if(!animating)
   {
-    vertical = All;
+    // if not animating, then this pan has completed right now.
+    self.SetProperty(Toolkit::ScrollView::Property::SCROLLING, false);
+    mScrolling = false;
 
-    if(speed2 > flickSpeedThreshold2 || // exceeds flick threshold
-       mInAccessibilityPan)             // With AccessibilityPan its easier to move between snap positions
+    // If we have no duration, then in the next update frame, we will be at the position specified as we just set.
+    // In this scenario, we cannot return the currentScrollPosition as this is out-of-date and should instead return the requested final position
+    Vector2 completedPosition(currentScrollPosition);
+    if(duration <= Math::MACHINE_EPSILON_10)
     {
-      if((angle >= M_PI_2 - orthoAngleRange) && (angle < M_PI_2 + orthoAngleRange)) // Swiping South
-      {
-        biasY = 0.0f, vertical = Up;
-      }
-      else if((angle >= -M_PI_2 - orthoAngleRange) && (angle < -M_PI_2 + orthoAngleRange)) // Swiping North
-      {
-        biasY = 1.0f, vertical = Down;
-      }
+      completedPosition = position;
     }
-  }
 
-  // isFlick: Whether this gesture is a flick or not.
-  bool isFlick = (horizontal != All || vertical != All);
-  // isFreeFlick: Whether this gesture is a flick under free panning criteria.
-  bool isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD * FREE_FLICK_SPEED_THRESHOLD);
-
-  if(isFlick || isFreeFlick)
-  {
-    positionDuration = Vector2::ONE * mFlickDuration;
-    alphaFunction    = mFlickAlphaFunction;
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 2 [%.2f, %.2f]", this, completedPosition.x, completedPosition.y);
+    SetScrollUpdateNotification(false);
+    mScrollCompletedSignal.Emit(completedPosition);
   }
+}
 
-  // Calculate next positionSnap ////////////////////////////////////////////////////////////
-
-  if(mActorAutoSnapEnabled)
-  {
-    Vector3 size = Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+void ScrollView::ScrollTo(const Vector2& position)
+{
+  ScrollTo(position, mSnapDuration);
+}
 
-    Actor child = FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f), horizontal, vertical);
+void ScrollView::ScrollTo(const Vector2& position, float duration)
+{
+  ScrollTo(position, duration, DIRECTION_BIAS_NONE, DIRECTION_BIAS_NONE);
+}
 
-    if(!child && isFlick)
-    {
-      // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
-      child = FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f));
-    }
+void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha)
+{
+  ScrollTo(position, duration, alpha, DIRECTION_BIAS_NONE, DIRECTION_BIAS_NONE);
+}
 
-    if(child)
-    {
-      Vector2 position = Self().GetCurrentProperty<Vector2>(Toolkit::ScrollView::Property::SCROLL_POSITION);
+void ScrollView::ScrollTo(const Vector2& position, float duration, DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  ScrollTo(position, duration, mSnapAlphaFunction, horizontalBias, verticalBias);
+}
 
-      // Get center-point of the Actor.
-      Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
+void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha, DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  DALI_LOG_SCROLL_STATE("[0x%X] position[%.2f, %.2f] duration[%.2f], bias[%d, %d]", this, position.x, position.y, duration, int(horizontalBias), int(verticalBias));
+  TransformTo(position, duration, alpha, horizontalBias, verticalBias);
+}
 
-      if(mRulerX->IsEnabled())
-      {
-        positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
-      }
-      if(mRulerY->IsEnabled())
-      {
-        positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
-      }
-    }
-  }
+void ScrollView::ScrollTo(unsigned int page)
+{
+  ScrollTo(page, mSnapDuration);
+}
 
-  Vector2 startPosition = positionSnap;
-  positionSnap.x        = -mRulerX->Snap(-positionSnap.x, biasX); // NOTE: X & Y rulers think in -ve coordinate system.
-  positionSnap.y        = -mRulerY->Snap(-positionSnap.y, biasY); // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
+void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
+{
+  Vector2      position;
+  unsigned int volume;
+  unsigned int libraries;
 
-  Vector2 clampDelta(Vector2::ZERO);
-  ClampPosition(positionSnap);
+  // The position to scroll to is continuous and linear
+  // unless a domain has been enabled on the X axis.
+  // or if WrapMode has been enabled.
+  bool carryX = mRulerX->GetDomain().enabled | mWrapMode;
+  bool carryY = mRulerY->GetDomain().enabled | mWrapMode;
 
-  if((mRulerX->GetType() == Ruler::FREE || mRulerY->GetType() == Ruler::FREE) && isFreeFlick && !mActorAutoSnapEnabled)
-  {
-    // Calculate target position based on velocity of flick.
+  position.x = mRulerX->GetPositionFromPage(page, volume, carryX);
+  position.y = mRulerY->GetPositionFromPage(volume, libraries, carryY);
 
-    // a = Deceleration (Set to diagonal stage length * friction coefficient)
-    // u = Initial Velocity (Flick velocity)
-    // v = 0 (Final Velocity)
-    // t = Time (Velocity / Deceleration)
-    Vector2 stageSize   = Stage::GetCurrent().GetSize();
-    float   stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
-    float   a           = (stageLength * mFrictionCoefficient);
-    Vector3 u           = Vector3(velocity.x, velocity.y, 0.0f) * mFlickSpeedCoefficient;
-    float   speed       = u.Length();
-    u /= speed;
+  ScrollTo(position, duration, bias, bias);
+}
 
-    // TODO: Change this to a decay function. (faster you flick, the slower it should be)
-    speed = std::min(speed, stageLength * mMaxFlickSpeed);
-    u *= speed;
-    alphaFunction = ConstantDecelerationAlphaFunction;
+void ScrollView::ScrollTo(Actor& actor)
+{
+  ScrollTo(actor, mSnapDuration);
+}
 
-    float t = speed / a;
+void ScrollView::ScrollTo(Actor& actor, float duration)
+{
+  DALI_ASSERT_ALWAYS(actor.GetParent() == Self());
 
-    if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::FREE)
-    {
-      positionSnap.x += t * u.x * 0.5f;
-    }
+  Actor   self        = Self();
+  Vector3 size        = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
+  Vector3 position    = actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
+  Vector2 prePosition = GetPropertyPrePosition();
+  position.GetVectorXY() -= prePosition;
 
-    if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::FREE)
-    {
-      positionSnap.y += t * u.y * 0.5f;
-    }
+  ScrollTo(Vector2(position.x - size.width * 0.5f, position.y - size.height * 0.5f), duration);
+}
 
-    clampDelta = positionSnap;
-    ClampPosition(positionSnap);
-    if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
-    {
-      clampDelta -= positionSnap;
-      clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, mMaxOvershoot.x) : std::max(clampDelta.x, -mMaxOvershoot.x);
-      clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, mMaxOvershoot.y) : std::max(clampDelta.y, -mMaxOvershoot.y);
-    }
-    else
-    {
-      clampDelta = Vector2::ZERO;
-    }
+Actor ScrollView::FindClosestActor()
+{
+  Actor   self = Self();
+  Vector3 size = self.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
 
-    // If Axis is Free and has velocity, then calculate time taken
-    // to reach target based on velocity in axis.
-    if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::FREE)
-    {
-      float deltaX = fabsf(startPosition.x - positionSnap.x);
+  return FindClosestActorToPosition(Vector3(size.width * 0.5f, size.height * 0.5f, 0.0f));
+}
 
-      if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
-      {
-        positionDuration.x = fabsf(deltaX / u.x);
-      }
-      else
-      {
-        positionDuration.x = 0;
-      }
-    }
+Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
+{
+  return ::FindClosestActorToPosition(Self(), mInternalActor, position, dirX, dirY, dirZ);
+}
 
-    if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::FREE)
-    {
-      float deltaY = fabsf(startPosition.y - positionSnap.y);
+bool ScrollView::ScrollToSnapPoint()
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this);
+  Vector2 stationaryVelocity = Vector2(0.0f, 0.0f);
+  return SnapWithVelocity(stationaryVelocity);
+}
 
-      if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
-      {
-        positionDuration.y = fabsf(deltaY / u.y);
-      }
-      else
-      {
-        positionDuration.y = 0;
-      }
-    }
-  }
+bool ScrollView::SnapWithVelocity(Vector2 velocity)
+{
+  Vector2       positionSnap     = mScrollPrePosition;
+  Vector2       positionDuration = Vector2::ONE * mSnapDuration;
+  AlphaFunction alphaFunction    = mSnapAlphaFunction;
+  bool          isFlick;
+  bool          isFreeFlick;
 
-  if(IsOvershootEnabled())
-  {
-    // Scroll to the end of the overshoot only when overshoot is enabled.
-    positionSnap += clampDelta;
-  }
+  ::SnapWithVelocity(*this, mRulerX, mRulerY, mLockAxis, velocity, mMaxOvershoot, positionSnap, positionDuration, alphaFunction, mInAccessibilityPan, isFlick, isFreeFlick);
 
   bool animating = AnimateTo(positionSnap, positionDuration, alphaFunction, false, DIRECTION_BIAS_NONE, DIRECTION_BIAS_NONE, isFlick || isFreeFlick ? FLICK : SNAP);
 
@@ -1698,7 +1233,7 @@ bool ScrollView::AnimateTo(const Vector2& position, const Vector2& positionDurat
   // Position Delta ///////////////////////////////////////////////////////
   if(positionChanged)
   {
-    UpdateMainInternalConstraint();
+    mConstraints.UpdateMainInternalConstraint(*this);
     if(mWrapMode && findShortcuts)
     {
       // In Wrap Mode, the shortest distance is a little less intuitive...
@@ -1771,7 +1306,7 @@ void ScrollView::EnableScrollOvershoot(bool enable)
     }
   }
 
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
 }
 
 void ScrollView::AddOverlay(Actor actor)
@@ -1826,7 +1361,7 @@ Toolkit::ScrollView::SnapStartedSignalType& ScrollView::SnapStartedSignal()
 bool ScrollView::AccessibleImpl::ScrollToChild(Actor child)
 {
   auto scrollView = Dali::Toolkit::ScrollView::DownCast(Self());
-  if (Toolkit::GetImpl(scrollView).FindClosestActor() == child)
+  if(Toolkit::GetImpl(scrollView).FindClosestActor() == child)
   {
     return false;
   }
@@ -1963,7 +1498,7 @@ void ScrollView::OnSizeSet(const Vector3& size)
     }
   }
   UpdatePropertyDomain();
-  UpdateMainInternalConstraint();
+  mConstraints.UpdateMainInternalConstraint(*this);
   if(IsOvershootEnabled())
   {
     mOvershootIndicator->Reset();
@@ -2503,7 +2038,7 @@ void ScrollView::OnPan(const PanGesture& gesture)
       self.SetProperty(Toolkit::ScrollView::Property::PANNING, true);
       self.SetProperty(Toolkit::ScrollView::Property::START_PAGE_POSITION, Vector3(position.x, position.y, 0.0f));
 
-      UpdateMainInternalConstraint();
+      mConstraints.UpdateMainInternalConstraint(*this);
       Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
       if(scrollBar && mTransientScrollBar)
       {
@@ -2546,9 +2081,9 @@ void ScrollView::OnPan(const PanGesture& gesture)
         mPanning      = false;
         self.SetProperty(Toolkit::ScrollView::Property::PANNING, false);
 
-        if(mScrollMainInternalPrePositionConstraint)
+        if(mConstraints.mScrollMainInternalPrePositionConstraint)
         {
-          mScrollMainInternalPrePositionConstraint.Remove();
+          mConstraints.mScrollMainInternalPrePositionConstraint.Remove();
         }
 
         Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
@@ -2704,8 +2239,7 @@ void ScrollView::ClampPosition(Vector2& position, ClampState2D& clamped) const
 {
   Vector3 size = Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE);
 
-  position.x = -mRulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);  // NOTE: X & Y rulers think in -ve coordinate system.
-  position.y = -mRulerY->Clamp(-position.y, size.height, 1.0f, clamped.y); // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
+  ::ClampPosition(size, mRulerX, mRulerY, position, clamped);
 }
 
 void ScrollView::WrapPosition(Vector2& position) const
@@ -2727,168 +2261,6 @@ void ScrollView::WrapPosition(Vector2& position) const
   }
 }
 
-void ScrollView::UpdateMainInternalConstraint()
-{
-  // TODO: Only update the constraints which have changed, rather than remove all and add all again.
-  // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
-  Actor              self = Self();
-  PanGestureDetector detector(GetPanGestureDetector());
-
-  if(mScrollMainInternalPositionConstraint)
-  {
-    mScrollMainInternalPositionConstraint.Remove();
-    mScrollMainInternalDeltaConstraint.Remove();
-    mScrollMainInternalFinalConstraint.Remove();
-    mScrollMainInternalRelativeConstraint.Remove();
-    mScrollMainInternalDomainConstraint.Remove();
-    mScrollMainInternalPrePositionMaxConstraint.Remove();
-  }
-  if(mScrollMainInternalPrePositionConstraint)
-  {
-    mScrollMainInternalPrePositionConstraint.Remove();
-  }
-
-  // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
-  // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
-
-  // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
-  Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
-
-  if(mLockAxis == LockVertical)
-  {
-    initialPanMask.y = 0.0f;
-  }
-  else if(mLockAxis == LockHorizontal)
-  {
-    initialPanMask.x = 0.0f;
-  }
-
-  if(mPanning)
-  {
-    mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>(self,
-                                                                        Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
-                                                                        InternalPrePositionConstraint(mPanStartPosition,
-                                                                                                      initialPanMask,
-                                                                                                      mAxisAutoLock,
-                                                                                                      mAxisAutoLockGradient,
-                                                                                                      mLockAxis,
-                                                                                                      mMaxOvershoot,
-                                                                                                      mRulerX,
-                                                                                                      mRulerY));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::LOCAL_POSITION));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(detector, PanGestureDetector::Property::PANNING));
-    mScrollMainInternalPrePositionConstraint.AddSource(Source(self, Actor::Property::SIZE));
-    mScrollMainInternalPrePositionConstraint.Apply();
-  }
-
-  // 2. Second calculate the clamped position (actual position)
-  mScrollMainInternalPositionConstraint = Constraint::New<Vector2>(self,
-                                                                   Toolkit::ScrollView::Property::SCROLL_POSITION,
-                                                                   InternalPositionConstraint(mRulerX->GetDomain(),
-                                                                                              mRulerY->GetDomain(),
-                                                                                              mWrapMode));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalPositionConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalPositionConstraint.AddSource(Source(self, Actor::Property::SIZE));
-  mScrollMainInternalPositionConstraint.Apply();
-
-  mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint);
-  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalDeltaConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET));
-  mScrollMainInternalDeltaConstraint.Apply();
-
-  mScrollMainInternalFinalConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_FINAL, InternalFinalConstraint(FinalDefaultAlphaFunction, FinalDefaultAlphaFunction));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_X));
-  mScrollMainInternalFinalConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::OVERSHOOT_Y));
-  mScrollMainInternalFinalConstraint.Apply();
-
-  mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>(self, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint);
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalRelativeConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalRelativeConstraint.Apply();
-
-  mScrollMainInternalDomainConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint);
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalDomainConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalDomainConstraint.Apply();
-
-  mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint);
-  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  mScrollMainInternalPrePositionMaxConstraint.AddSource(LocalSource(Actor::Property::SIZE));
-  mScrollMainInternalPrePositionMaxConstraint.Apply();
-
-  // When panning we want to make sure overshoot values are affected by pre position and post position
-  SetOvershootConstraintsEnabled(!mWrapMode);
-}
-
-void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
-{
-  Actor self(Self());
-  // remove and reset, it may now be in wrong order with the main internal constraints
-  if(mScrollMainInternalOvershootXConstraint)
-  {
-    mScrollMainInternalOvershootXConstraint.Remove();
-    mScrollMainInternalOvershootXConstraint.Reset();
-    mScrollMainInternalOvershootYConstraint.Remove();
-    mScrollMainInternalOvershootYConstraint.Reset();
-  }
-  if(enabled)
-  {
-    mScrollMainInternalOvershootXConstraint = Constraint::New<float>(self, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(mMaxOvershoot.x));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-    mScrollMainInternalOvershootXConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL));
-    mScrollMainInternalOvershootXConstraint.Apply();
-
-    mScrollMainInternalOvershootYConstraint = Constraint::New<float>(self, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(mMaxOvershoot.y));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::ScrollView::Property::SCROLL_POSITION));
-    mScrollMainInternalOvershootYConstraint.AddSource(LocalSource(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL));
-    mScrollMainInternalOvershootYConstraint.Apply();
-  }
-  else
-  {
-    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
-    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
-  }
-}
-
-void ScrollView::SetInternalConstraints()
-{
-  // Internal constraints (applied to target ScrollBase Actor itself) /////////
-  UpdateMainInternalConstraint();
-
-  // User definable constraints to apply to all child actors //////////////////
-  Actor self = Self();
-
-  // Apply some default constraints to ScrollView & its bound actors
-  // Movement + Wrap function
-
-  Constraint constraint;
-
-  // MoveActor (scrolling)
-  constraint = Constraint::New<Vector3>(self, Actor::Property::POSITION, MoveActorConstraint);
-  constraint.AddSource(Source(self, Toolkit::ScrollView::Property::SCROLL_POSITION));
-  constraint.SetRemoveAction(Constraint::DISCARD);
-  ApplyConstraintToBoundActors(constraint);
-
-  // WrapActor (wrap functionality)
-  constraint = Constraint::New<Vector3>(self, Actor::Property::POSITION, WrapActorConstraint);
-  constraint.AddSource(LocalSource(Actor::Property::SCALE));
-  constraint.AddSource(LocalSource(Actor::Property::ANCHOR_POINT));
-  constraint.AddSource(LocalSource(Actor::Property::SIZE));
-  constraint.AddSource(Source(self, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN));
-  constraint.AddSource(Source(self, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX));
-  constraint.AddSource(Source(self, Toolkit::ScrollView::Property::WRAP));
-  constraint.SetRemoveAction(Constraint::DISCARD);
-  ApplyConstraintToBoundActors(constraint);
-}
-
 void ScrollView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
 {
   Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
@@ -3051,6 +2423,31 @@ void ScrollView::SetScrollMode(const Property::Map& scrollModeMap)
   SetRulerY(rulerY);
 }
 
+ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
+{
+  if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
+     currentLockAxis == ScrollView::LockPossible)
+  {
+    float dx = fabsf(panDelta.x);
+    float dy = fabsf(panDelta.y);
+    if(dx * lockGradient >= dy)
+    {
+      // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockVertical;
+    }
+    else if(dy * lockGradient > dx)
+    {
+      // 0.36:1 gradient to the vertical (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockHorizontal;
+    }
+    else
+    {
+      currentLockAxis = ScrollView::LockNone;
+    }
+  }
+  return currentLockAxis;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index aee050e..4d871a7 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-constraints.h>
 
 namespace Dali
 {
@@ -103,42 +104,66 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetScrollSnapAlphaFunction
    */
-  AlphaFunction GetScrollSnapAlphaFunction() const;
+  AlphaFunction GetScrollSnapAlphaFunction() const
+  {
+    return mSnapAlphaFunction;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollSnapAlphaFunction
    */
-  void SetScrollSnapAlphaFunction(AlphaFunction alpha);
+  void SetScrollSnapAlphaFunction(AlphaFunction alpha)
+  {
+    mSnapAlphaFunction = alpha;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetScrollFlickAlphaFunction
    */
-  AlphaFunction GetScrollFlickAlphaFunction() const;
+  AlphaFunction GetScrollFlickAlphaFunction() const
+  {
+    return mFlickAlphaFunction;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollFlickAlphaFunction
    */
-  void SetScrollFlickAlphaFunction(AlphaFunction alpha);
+  void SetScrollFlickAlphaFunction(AlphaFunction alpha)
+  {
+    mFlickAlphaFunction = alpha;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetScrollSnapDuration
    */
-  float GetScrollSnapDuration() const;
+  float GetScrollSnapDuration() const
+  {
+    return mSnapDuration;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollSnapDuration
    */
-  void SetScrollSnapDuration(float time);
+  void SetScrollSnapDuration(float time)
+  {
+    mSnapDuration = time;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetScrollFlickDuration
    */
-  float GetScrollFlickDuration() const;
+  float GetScrollFlickDuration() const
+  {
+    return mFlickDuration;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollFlickDuration
    */
-  void SetScrollFlickDuration(float time);
+  void SetScrollFlickDuration(float time)
+  {
+    mFlickDuration = time;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::ApplyEffect
@@ -168,12 +193,18 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetRulerX
    */
-  const RulerPtr GetRulerX() const;
+  const RulerPtr GetRulerX() const
+  {
+    return mRulerX;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetRulerY
    */
-  const RulerPtr GetRulerY() const;
+  const RulerPtr GetRulerY() const
+  {
+    return mRulerY;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetRulerX
@@ -190,7 +221,10 @@ public:
    *
    * @return whether the touch sensitivity is true or false.
    */
-  bool GetScrollSensitive();
+  bool GetScrollSensitive()
+  {
+    return mSensitive;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollSensitive
@@ -205,19 +239,28 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::SetSnapOvershootAlphaFunction
    */
-  void SetSnapOvershootAlphaFunction(AlphaFunction alpha);
+  void SetSnapOvershootAlphaFunction(AlphaFunction alpha)
+  {
+    mSnapOvershootAlphaFunction = alpha;
+  }
 
   /**
    * Retrieve the duartion of Snap Overshoot animation
    *
    * @return the duration.
    */
-  float GetSnapOvershootDuration();
+  float GetSnapOvershootDuration()
+  {
+    return mSnapOvershootDuration;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetSnapOvershootDuration
    */
-  void SetSnapOvershootDuration(float duration);
+  void SetSnapOvershootDuration(float duration)
+  {
+    mSnapOvershootDuration = duration;
+  }
 
   /**
    * Retrieve whether Actor Auto-Snap mode is enabled or not.
@@ -229,7 +272,10 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::SetActorAutoSnap
    */
-  void SetActorAutoSnap(bool enable);
+  void SetActorAutoSnap(bool enable)
+  {
+    mActorAutoSnapEnabled = enable;
+  }
 
   /**
    * Enables or Disables Auto Resizing mode for ScrollView contents.
@@ -251,7 +297,10 @@ public:
    *
    * @return Wrap Mode Enabled flag.
    */
-  bool GetWrapMode() const;
+  bool GetWrapMode() const
+  {
+    return mWrapMode;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetWrapMode
@@ -261,17 +310,26 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetScrollupdateDistance
    */
-  int GetScrollUpdateDistance() const;
+  int GetScrollUpdateDistance() const
+  {
+    return mScrollUpdateDistance;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetScrollUpdateDistance
    */
-  void SetScrollUpdateDistance(int distance);
+  void SetScrollUpdateDistance(int distance)
+  {
+    mScrollUpdateDistance = distance;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetAxisAutoLock
    */
-  bool GetAxisAutoLock() const;
+  bool GetAxisAutoLock() const
+  {
+    return mAxisAutoLock;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetAxisAutoLock
@@ -281,7 +339,10 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetAxisAutoLockGradient
    */
-  float GetAxisAutoLockGradient() const;
+  float GetAxisAutoLockGradient() const
+  {
+    return mAxisAutoLockGradient;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetAxisAutoLockGradient
@@ -291,7 +352,10 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetFrictionCoefficient
    */
-  float GetFrictionCoefficient() const;
+  float GetFrictionCoefficient() const
+  {
+    return mFrictionCoefficient;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetFrictionCoefficient
@@ -301,52 +365,82 @@ public:
   /**
    * @copydoc Toolkit::ScrollView::GetFlickSpeedCoefficient
    */
-  float GetFlickSpeedCoefficient() const;
+  float GetFlickSpeedCoefficient() const
+  {
+    return mFlickSpeedCoefficient;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetFlickSpeedCoefficient
    */
-  void SetFlickSpeedCoefficient(float speed);
+  void SetFlickSpeedCoefficient(float speed)
+  {
+    mFlickSpeedCoefficient = speed;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetMinimumDistanceForFlick
    */
-  Vector2 GetMinimumDistanceForFlick() const;
+  Vector2 GetMinimumDistanceForFlick() const
+  {
+    return mMinFlickDistance;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetMinimumDistanceForFlick
    */
-  void SetMinimumDistanceForFlick(const Vector2& distance);
+  void SetMinimumDistanceForFlick(const Vector2& distance)
+  {
+    mMinFlickDistance = distance;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetMinimumSpeedForFlick
    */
-  float GetMinimumSpeedForFlick() const;
+  float GetMinimumSpeedForFlick() const
+  {
+    return mFlickSpeedThreshold;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetMinimumSpeedForFlick
    */
-  void SetMinimumSpeedForFlick(float speed);
+  void SetMinimumSpeedForFlick(float speed)
+  {
+    mFlickSpeedThreshold = speed;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetMaxFlickSpeed
    */
-  float GetMaxFlickSpeed() const;
+  float GetMaxFlickSpeed() const
+  {
+    return mMaxFlickSpeed;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetMaxFlickSpeed
    */
-  void SetMaxFlickSpeed(float speed);
+  void SetMaxFlickSpeed(float speed)
+  {
+    mMaxFlickSpeed = speed;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetWheelScrollDistanceStep
    */
-  Vector2 GetWheelScrollDistanceStep() const;
+  Vector2 GetWheelScrollDistanceStep() const
+  {
+    return mWheelScrollDistanceStep;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::SetWheelScrollDistanceStep
    */
-  void SetWheelScrollDistanceStep(Vector2 step);
+  void SetWheelScrollDistanceStep(Vector2 step)
+  {
+    mWheelScrollDistanceStep = step;
+  }
 
   /**
    * @copydoc Toolkit::ScrollView::GetCurrentPage
@@ -765,26 +859,6 @@ private:
    */
   void WrapPosition(Vector2& position) const;
 
-  /**
-   * Updates the main internal scroll constraints with new ruler and domain
-   * values
-   */
-  void UpdateMainInternalConstraint();
-
-  /**
-   * Enables/disables the overshoot constraints
-   *
-   * @param[in] enabled whether to enable or disable the overshoot constraints
-   */
-  void SetOvershootConstraintsEnabled(bool enabled);
-
-  /**
-   * Sets internal constraints for this ScrollView.
-   * Many of these internal constraints are based on properties within
-   * ScrollView.
-   */
-  void SetInternalConstraints();
-
 protected:
   struct AccessibleImpl : public Scrollable::AccessibleImpl
   {
@@ -865,6 +939,8 @@ private:
   ScrollView& operator=(const ScrollView& rhs);
 
 private:
+  ScrollViewConstraints mConstraints;
+
   unsigned long mTouchDownTime; ///< The touch down time
 
   int     mGestureStackDepth; ///< How many gestures are currently occuring.
@@ -922,17 +998,6 @@ private:
 
   Vector2 mWheelScrollDistanceStep; ///< The step of scroll distance in actor coordinates in X and Y axes for each wheel event received.
 
-  //ScrollInternalConstraintsPtr mScrollInternalConstraints;
-  Constraint mScrollMainInternalPrePositionConstraint;
-  Constraint mScrollMainInternalPositionConstraint;
-  Constraint mScrollMainInternalOvershootXConstraint;
-  Constraint mScrollMainInternalOvershootYConstraint;
-  Constraint mScrollMainInternalDeltaConstraint;
-  Constraint mScrollMainInternalFinalConstraint;
-  Constraint mScrollMainInternalRelativeConstraint;
-  Constraint mScrollMainInternalDomainConstraint;
-  Constraint mScrollMainInternalPrePositionMaxConstraint;
-
   ScrollOvershootIndicatorPtr    mOvershootIndicator;
   WeakHandle<Toolkit::ScrollBar> mScrollBar;
 
@@ -953,8 +1018,21 @@ private:
   bool mCanScrollHorizontal : 1;        ///< Local value of our property to check against
   bool mCanScrollVertical : 1;          ///< Local value of our property to check against
   bool mTransientScrollBar : 1;         ///< True if scroll-bar should be automatically show/hidden during/after panning
+
+  friend ScrollViewConstraints;
 };
 
+/**
+ * Returns whether to lock scrolling to a particular axis
+ *
+ * @param[in] panDelta Distance panned since gesture started
+ * @param[in] currentLockAxis The current lock axis value
+ * @param[in] lockGradient How quickly to lock to a particular axis
+ *
+ * @return The new axis lock state
+ */
+ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient);
+
 } // namespace Internal
 
 // Helpers for public-api forwarding methods
index 4b3e019..9aec5ba 100644 (file)
@@ -51,7 +51,7 @@ bool FitToChild(Actor actor, Dimension::Type dimension)
 // currently not called from code so compiler will optimize these away, kept here for future debugging
 
 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
-#define TV_LOG(fmt, args, ...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ##args)
+#define TV_LOG(fmt, args, ...) Debug::LogMessageWithFunctionLine(Debug::DebugInfo, TABLEVIEW_TAG fmt, ##args)
 //#define TABLEVIEW_DEBUG 1
 
 #if defined(TABLEVIEW_DEBUG)
diff --git a/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp b/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp
new file mode 100644 (file)
index 0000000..7331f3e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/actors/layer.h>
+
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
+#include <dali-toolkit/internal/text/text-view.h>
+
+namespace Dali::Toolkit::Internal
+{
+void CommonTextUtils::RenderText(
+  Actor                            textActor,
+  Text::RendererPtr                renderer,
+  Text::ControllerPtr              controller,
+  Text::DecoratorPtr               decorator,
+  float                            alignmentOffset,
+  Actor&                           renderableActor,
+  Actor&                           backgroundActor,
+  Toolkit::Control&                stencil,
+  std::vector<Actor>&              clippingDecorationActors,
+  Text::Controller::UpdateTextType updateTextType)
+{
+  Actor newRenderableActor;
+
+  if(Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType))
+  {
+    if(renderer)
+    {
+      newRenderableActor = renderer->Render(controller->GetView(),
+                                            textActor,
+                                            Property::INVALID_INDEX, // Animatable property not supported
+                                            alignmentOffset,
+                                            DepthIndex::CONTENT);
+    }
+
+    if(renderableActor != newRenderableActor)
+    {
+      UnparentAndReset(backgroundActor);
+      UnparentAndReset(renderableActor);
+      renderableActor = newRenderableActor;
+
+      if(renderableActor)
+      {
+        backgroundActor = controller->CreateBackgroundActor();
+      }
+    }
+  }
+
+  if(renderableActor)
+  {
+    const Vector2& scrollOffset = controller->GetTextModel()->GetScrollPosition();
+
+    float renderableActorPositionX, renderableActorPositionY;
+
+    if(stencil)
+    {
+      renderableActorPositionX = scrollOffset.x + alignmentOffset;
+      renderableActorPositionY = scrollOffset.y;
+    }
+    else
+    {
+      Extents padding;
+      padding = textActor.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
+
+      // Support Right-To-Left of padding
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(textActor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
+      {
+        std::swap(padding.start, padding.end);
+      }
+
+      renderableActorPositionX = scrollOffset.x + alignmentOffset + padding.start;
+      renderableActorPositionY = scrollOffset.y + padding.top;
+    }
+
+    renderableActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY));
+
+    // Make sure the actors are parented correctly with/without clipping
+    Actor self = stencil ? stencil : textActor;
+
+    Actor highlightActor;
+
+    for(std::vector<Actor>::iterator it    = clippingDecorationActors.begin(),
+                                     endIt = clippingDecorationActors.end();
+        it != endIt;
+        ++it)
+    {
+      self.Add(*it);
+      it->LowerToBottom();
+
+      if(it->GetProperty<std::string>(Dali::Actor::Property::NAME) == "HighlightActor")
+      {
+        highlightActor = *it;
+      }
+    }
+    clippingDecorationActors.clear();
+
+    self.Add(renderableActor);
+
+    if(backgroundActor)
+    {
+      if(decorator && decorator->IsHighlightVisible())
+      {
+        self.Add(backgroundActor);
+        backgroundActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY)); // In text field's coords.
+        backgroundActor.LowerBelow(highlightActor);
+      }
+      else
+      {
+        renderableActor.Add(backgroundActor);
+        backgroundActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); // In renderable actor's coords.
+        backgroundActor.LowerToBottom();
+      }
+    }
+  }
+}
+
+} // namespace Dali::Toolkit::Internal
diff --git a/dali-toolkit/internal/controls/text-controls/common-text-utils.h b/dali-toolkit/internal/controls/text-controls/common-text-utils.h
new file mode 100644 (file)
index 0000000..f2eaba7
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_CONTROLS_COMMON_TEXT_UTILS_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_CONTROLS_COMMON_TEXT_UTILS_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+#include <dali/public-api/actors/actor.h>
+
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali::Toolkit::Internal
+{
+class CommonTextUtils
+{
+public:
+  /**
+   * Common method to render text, setting up background, foreground actors with decorators/stencil.
+   * @param[in] textActor The TextEditor or TextField
+   * @param[in] renderer pointer to the text renderer
+   * @param[in] controller pointer to the text controller
+   * @param[in] decorator pointer to the text decorator
+   * @param[in] alignmentOffset Alignment offset
+   * @param[in,out] renderableActor Actor for rendering text
+   * @param[in,out] backgroundActor Actor for rendering background
+   * @param[in,out] stencil Clipping actor
+   * @param[in,out] clippingDecorationActors Clipping decoration actors
+   * @param[in] updateTextType How the text has been updated
+   */
+  static void RenderText(
+    Actor                            textActor,
+    Text::RendererPtr                renderer,
+    Text::ControllerPtr              controller,
+    Text::DecoratorPtr               decorator,
+    float                            alignmentOffset,
+    Actor&                           renderableActor,
+    Actor&                           backgroundActor,
+    Toolkit::Control&                stencil,
+    std::vector<Actor>&              clippingDecorationActors,
+    Text::Controller::UpdateTextType updateTextType);
+};
+
+} // namespace Dali::Toolkit::Internal
+
+#endif //DALI_TOOLKIT_INTERNAL_TEXT_CONTROLS_COMMON_TEXT_UTILS_H
index 0bdc8c1..0259471 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/devel-api/object/property-helper-devel.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/layer.h>
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <limits>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 #include <dali-toolkit/devel-api/text/rendering-backend.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
+#include <dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/text/rendering/text-backend.h>
 #include <dali-toolkit/internal/text/text-effects-style.h>
 
 using namespace Dali::Toolkit::Text;
 
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gTextEditorLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
+#endif
+
 namespace Dali
 {
 namespace Toolkit
@@ -56,10 +62,6 @@ namespace Internal
 {
 namespace // unnamed namespace
 {
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
-#endif
-
 const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND;
 const float        DEFAULT_SCROLL_SPEED      = 1200.f; ///< The default scroll speed for the text editor in pixels/second.
 } // unnamed namespace
@@ -165,22 +167,55 @@ DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "selectionCleared",      SIGNAL_SE
 DALI_TYPE_REGISTRATION_END()
 // clang-format on
 
-const char* const IMAGE_MAP_FILENAME_STRING = "filename";
-
-/// Retrieves a filename from a value that is a Property::Map
-std::string GetImageFileNameFromPropertyValue(const Property::Value& value)
+Toolkit::TextEditor::InputStyle::Mask ConvertInputStyle(Text::InputStyle::Mask inputStyleMask)
 {
-  std::string          filename;
-  const Property::Map* map = value.GetMap();
-  if(map)
+  Toolkit::TextEditor::InputStyle::Mask editorInputStyleMask = Toolkit::TextEditor::InputStyle::NONE;
+
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_COLOR))
   {
-    const Property::Value* filenameValue = map->Find(IMAGE_MAP_FILENAME_STRING);
-    if(filenameValue)
-    {
-      filenameValue->Get(filename);
-    }
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::COLOR);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_FAMILY))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_FAMILY);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_POINT_SIZE))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::POINT_SIZE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WEIGHT))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WIDTH))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_SLANT))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_LINE_SPACING))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::LINE_SPACING);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_UNDERLINE))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::UNDERLINE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_SHADOW))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::SHADOW);
   }
-  return filename;
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_EMBOSS))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::EMBOSS);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_OUTLINE))
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::OUTLINE);
+  }
+  return editorInputStyleMask;
 }
 
 } // namespace
@@ -195,652 +230,21 @@ Toolkit::TextEditor TextEditor::New()
 
   // Second-phase init of the implementation
   // This can only be done after the CustomActor connection has been made...
-  impl->Initialize();
-
-  return handle;
-}
-
-void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
-{
-  Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast(Dali::BaseHandle(object));
-
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor SetProperty\n");
-
-  if(textEditor)
-  {
-    TextEditor& impl(GetImpl(textEditor));
-    DALI_ASSERT_DEBUG(impl.mController && "No text contoller");
-    DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
-
-    switch(index)
-    {
-      case Toolkit::DevelTextEditor::Property::RENDERING_BACKEND:
-      {
-        int backend = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend);
-
-        if(impl.mRenderingBackend != backend)
-        {
-          impl.mRenderingBackend = backend;
-          impl.mRenderer.Reset();
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::TEXT:
-      {
-        const std::string& text = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p TEXT %s\n", impl.mController.Get(), text.c_str());
-
-        impl.mController->SetText(text);
-        break;
-      }
-      case Toolkit::TextEditor::Property::TEXT_COLOR:
-      {
-        const Vector4& textColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
-
-        if(impl.mController->GetDefaultColor() != textColor)
-        {
-          impl.mController->SetDefaultColor(textColor);
-          impl.mController->SetInputColor(textColor);
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::FONT_FAMILY:
-      {
-        const std::string& fontFamily = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
-        impl.mController->SetDefaultFontFamily(fontFamily);
-        break;
-      }
-      case Toolkit::TextEditor::Property::FONT_STYLE:
-      {
-        SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::POINT_SIZE:
-      {
-        const float pointSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p POINT_SIZE %f\n", impl.mController.Get(), pointSize);
-
-        if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize))
-        {
-          impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE);
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
-      {
-        Text::HorizontalAlignment::Type alignment(static_cast<Text::HorizontalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(Text::GetHorizontalAlignmentEnumeration(value, alignment))
-        {
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
-          impl.mController->SetHorizontalAlignment(alignment);
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
-      {
-        const float threshold = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold);
-
-        impl.mDecorator->SetScrollThreshold(threshold);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_SPEED:
-      {
-        const float speed = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_SPEED %f\n", impl.mController.Get(), speed);
-
-        impl.mDecorator->SetScrollSpeed(speed);
-        break;
-      }
-      case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
-      {
-        const Vector4& color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetCursorColor(PRIMARY_CURSOR, color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
-      {
-        const Vector4& color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetCursorColor(SECONDARY_CURSOR, color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
-      {
-        const bool enable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable);
-
-        impl.mController->SetEnableCursorBlink(enable);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
-      {
-        const float interval = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval);
-
-        impl.mDecorator->SetCursorBlinkInterval(interval);
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
-      {
-        const float duration = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration);
-
-        impl.mDecorator->SetCursorBlinkDuration(duration);
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_WIDTH:
-      {
-        const int width = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_WIDTH %d\n", impl.mController.Get(), width);
-
-        impl.mDecorator->SetCursorWidth(width);
-        impl.mController->GetLayoutEngine().SetCursorWidth(width);
-        break;
-      }
-      case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
-      {
-        const std::string imageFileName = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
-
-        if(imageFileName.size())
-        {
-          impl.mDecorator->SetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_RELEASED, imageFileName);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
-      {
-        const std::string imageFileName = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
-
-        if(imageFileName.size())
-        {
-          impl.mDecorator->SetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_PRESSED, imageFileName);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
-      {
-        const Vector4 color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetHighlightColor(color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
-      {
-        const Rect<int>& box = value.Get<Rect<int> >();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height);
-
-        impl.mDecorator->SetBoundingBox(box);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_MARKUP:
-      {
-        const bool enableMarkup = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
-
-        impl.mController->SetMarkupProcessorEnabled(enableMarkup);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_COLOR:
-      {
-        const Vector4& inputColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a);
-
-        impl.mController->SetInputColor(inputColor);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
-      {
-        const std::string& fontFamily = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
-        impl.mController->SetInputFontFamily(fontFamily);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
-      {
-        SetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
-      {
-        const float pointSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize);
-        impl.mController->SetInputFontPointSize(pointSize);
-        break;
-      }
-      case Toolkit::TextEditor::Property::LINE_SPACING:
-      {
-        const float lineSpacing = value.Get<float>();
-        impl.mController->SetDefaultLineSpacing(lineSpacing);
-        impl.mRenderer.Reset();
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
-      {
-        const float lineSpacing = value.Get<float>();
-        impl.mController->SetInputLineSpacing(lineSpacing);
-        impl.mRenderer.Reset();
-        break;
-      }
-      case Toolkit::TextEditor::Property::UNDERLINE:
-      {
-        const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
-      {
-        const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SHADOW:
-      {
-        const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_SHADOW:
-      {
-        const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::EMBOSS:
-      {
-        const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_EMBOSS:
-      {
-        const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::OUTLINE:
-      {
-        const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_OUTLINE:
-      {
-        const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
-      {
-        const bool enable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor SMOOTH_SCROLL %d\n", enable);
-
-        impl.mScrollAnimationEnabled = enable;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
-      {
-        const float duration = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor SMOOTH_SCROLL_DURATION %f\n", duration);
-
-        impl.mScrollAnimationDuration = duration;
-        if(impl.mTextVerticalScroller)
-        {
-          impl.mTextVerticalScroller->SetDuration(duration);
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
-      {
-        const bool enable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor SHOW_SCROLL_BAR %d\n", enable);
-
-        impl.mScrollBarEnabled = enable;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
-      {
-        const float duration = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor SCROLL_BAR_SHOW_DURATION %f\n", duration);
-
-        impl.mAnimationPeriod.delaySeconds = duration;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
-      {
-        const float duration = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor SCROLL_BAR_FADE_DURATION %f\n", duration);
-
-        impl.mAnimationPeriod.durationSeconds = duration;
-        break;
-      }
-      case Toolkit::TextEditor::Property::PIXEL_SIZE:
-      {
-        const float pixelSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize);
-
-        if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize))
-        {
-          impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
-      {
-        const std::string& text = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor::OnPropertySet %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str());
-
-        impl.mController->SetPlaceholderText(Controller::PLACEHOLDER_TYPE_INACTIVE, text);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
-      {
-        const Vector4& textColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
-
-        if(impl.mController->GetPlaceholderTextColor() != textColor)
-        {
-          impl.mController->SetPlaceholderTextColor(textColor);
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_SELECTION:
-      {
-        const bool enableSelection = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection);
-        impl.mController->SetSelectionEnabled(enableSelection);
-        break;
-      }
-      case Toolkit::TextEditor::Property::PLACEHOLDER:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mController->SetPlaceholderProperty(*map);
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
-      {
-        Text::LineWrap::Mode lineWrapMode(static_cast<Text::LineWrap::Mode>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(GetLineWrapModeEnumeration(value, lineWrapMode))
-        {
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode);
-          impl.mController->SetLineWrapMode(lineWrapMode);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
-      {
-        const bool shiftSelection = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection);
-
-        impl.mController->SetShiftSelectionEnabled(shiftSelection);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
-      {
-        const bool grabHandleEnabled = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled);
-
-        impl.mController->SetGrabHandleEnabled(grabHandleEnabled);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
-      {
-        impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MAX_LENGTH:
-      {
-        const int max = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p MAX_LENGTH %d\n", impl.mController.Get(), max);
-
-        impl.mController->SetMaximumNumberOfCharacters(max);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
-      {
-        uint32_t start = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start);
-        impl.SetTextSelectionRange(&start, nullptr);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
-      {
-        uint32_t end = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end);
-        impl.SetTextSelectionRange(nullptr, &end);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
-      {
-        const bool editable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_EDITING %d\n", impl.mController.Get(), editable);
-        impl.SetEditable(editable);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
-      {
-        float horizontalScroll = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p HORIZONTAL_SCROLL_POSITION %d\n", impl.mController.Get(), horizontalScroll);
-        if(horizontalScroll >= 0.0f)
-        {
-          impl.ScrollBy(Vector2(horizontalScroll - impl.GetHorizontalScrollPosition(), 0));
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
-      {
-        float verticalScroll = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p VERTICAL_SCROLL_POSITION %d\n", impl.mController.Get(), verticalScroll);
-        if(verticalScroll >= 0.0f)
-        {
-          impl.ScrollBy(Vector2(0, verticalScroll - impl.GetVerticalScrollPosition()));
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
-      {
-        const float scale = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale);
-
-        if(!Equals(impl.mController->GetFontSizeScale(), scale))
-        {
-          impl.mController->SetFontSizeScale(scale);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
-      {
-        uint32_t position = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position);
-        if(impl.mController->SetPrimaryCursorPosition(position, impl.HasKeyInputFocus()))
-        {
-          impl.SetKeyInputFocus();
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::GRAB_HANDLE_COLOR:
-      {
-        const Vector4 color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p GRAB_HANDLE_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetHandleColor(color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
-      {
-        const bool grabHandlePopupEnabled = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
-
-        impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mInputMethodOptions.ApplyProperty(*map);
-        }
-        impl.mController->SetInputModePassword(impl.mInputMethodOptions.IsPassword());
-
-        Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
-        if(control == textEditor)
-        {
-          impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mController->SetInputFilterOption(*map);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ELLIPSIS:
-      {
-        const bool ellipsis = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
+  impl->Initialize();
 
-        impl.mController->SetTextElideEnabled(ellipsis);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
-      {
-        DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
-        {
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
-          impl.mController->SetEllipsisPosition(ellipsisPositionType);
-        }
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE:
-      {
-        const float minLineSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor %p MIN_LINE_SIZE %f\n", impl.mController.Get(), minLineSize);
+  return handle;
+}
 
-        impl.mController->SetDefaultLineSize(minLineSize);
-        impl.mRenderer.Reset();
-        break;
-      }
-    } // switch
-  }   // texteditor
+void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
+{
+  Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast(Dali::BaseHandle(object));
+
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor SetProperty\n");
+
+  if(textEditor)
+  {
+    PropertyHandler::SetProperty(textEditor, index, value);
+  }
 }
 
 Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index index)
@@ -851,390 +255,8 @@ Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index inde
 
   if(textEditor)
   {
-    TextEditor& impl(GetImpl(textEditor));
-    DALI_ASSERT_DEBUG(impl.mController && "No text contoller");
-    DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
-
-    switch(index)
-    {
-      case Toolkit::DevelTextEditor::Property::RENDERING_BACKEND:
-      {
-        value = impl.mRenderingBackend;
-        break;
-      }
-      case Toolkit::TextEditor::Property::TEXT:
-      {
-        std::string text;
-        impl.mController->GetText(text);
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p returning text: %s\n", impl.mController.Get(), text.c_str());
-        value = text;
-        break;
-      }
-      case Toolkit::TextEditor::Property::TEXT_COLOR:
-      {
-        value = impl.mController->GetDefaultColor();
-        break;
-      }
-      case Toolkit::TextEditor::Property::FONT_FAMILY:
-      {
-        value = impl.mController->GetDefaultFontFamily();
-        break;
-      }
-      case Toolkit::TextEditor::Property::FONT_STYLE:
-      {
-        GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::POINT_SIZE:
-      {
-        value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE);
-        break;
-      }
-      case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
-      {
-        const char* name = GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment());
-        if(name)
-        {
-          value = std::string(name);
-        }
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
-      {
-        value = impl.mDecorator->GetScrollThreshold();
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_SPEED:
-      {
-        value = impl.mDecorator->GetScrollSpeed();
-        break;
-      }
-      case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
-      {
-        value = impl.mDecorator->GetColor(PRIMARY_CURSOR);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
-      {
-        value = impl.mDecorator->GetColor(SECONDARY_CURSOR);
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
-      {
-        value = impl.mController->GetEnableCursorBlink();
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
-      {
-        value = impl.mDecorator->GetCursorBlinkInterval();
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
-      {
-        value = impl.mDecorator->GetCursorBlinkDuration();
-        break;
-      }
-      case Toolkit::TextEditor::Property::CURSOR_WIDTH:
-      {
-        value = impl.mDecorator->GetCursorWidth();
-        break;
-      }
-      case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
-      {
-        value = impl.mDecorator->GetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
-      {
-        value = impl.mDecorator->GetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
-      {
-        value = impl.mDecorator->GetHighlightColor();
-        break;
-      }
-      case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
-      {
-        Rect<int> boundingBox;
-        impl.mDecorator->GetBoundingBox(boundingBox);
-        value = boundingBox;
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_MARKUP:
-      {
-        value = impl.mController->IsMarkupProcessorEnabled();
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_COLOR:
-      {
-        value = impl.mController->GetInputColor();
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
-      {
-        value = impl.mController->GetInputFontFamily();
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
-      {
-        GetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
-      {
-        value = impl.mController->GetInputFontPointSize();
-        break;
-      }
-      case Toolkit::TextEditor::Property::LINE_SPACING:
-      {
-        value = impl.mController->GetDefaultLineSpacing();
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
-      {
-        value = impl.mController->GetInputLineSpacing();
-        break;
-      }
-      case Toolkit::TextEditor::Property::UNDERLINE:
-      {
-        GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
-      {
-        GetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SHADOW:
-      {
-        GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_SHADOW:
-      {
-        GetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::EMBOSS:
-      {
-        GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_EMBOSS:
-      {
-        GetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::OUTLINE:
-      {
-        GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::INPUT_OUTLINE:
-      {
-        GetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
-      {
-        value = impl.mScrollAnimationEnabled;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
-      {
-        value = impl.mScrollAnimationDuration;
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
-      {
-        value = impl.mScrollBarEnabled;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
-      {
-        value = impl.mAnimationPeriod.delaySeconds;
-        break;
-      }
-      case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
-      {
-        value = impl.mAnimationPeriod.durationSeconds;
-        break;
-      }
-      case Toolkit::TextEditor::Property::PIXEL_SIZE:
-      {
-        value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE);
-        break;
-      }
-      case Toolkit::TextEditor::Property::LINE_COUNT:
-      {
-        float width = textEditor.GetProperty(Actor::Property::SIZE_WIDTH).Get<float>();
-        value       = impl.mController->GetLineCount(width);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
-      {
-        std::string text;
-        impl.mController->GetPlaceholderText(Controller::PLACEHOLDER_TYPE_INACTIVE, text);
-        value = text;
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
-      {
-        value = impl.mController->GetPlaceholderTextColor();
-        break;
-      }
-      case Toolkit::TextEditor::Property::ENABLE_SELECTION:
-      {
-        value = impl.mController->IsSelectionEnabled();
-        break;
-      }
-      case Toolkit::TextEditor::Property::PLACEHOLDER:
-      {
-        Property::Map map;
-        impl.mController->GetPlaceholderProperty(map);
-        value = map;
-        break;
-      }
-      case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
-      {
-        value = impl.mController->GetLineWrapMode();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
-      {
-        value = impl.mController->IsShiftSelectionEnabled();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
-      {
-        value = impl.mController->IsGrabHandleEnabled();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
-      {
-        value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MAX_LENGTH:
-      {
-        value = impl.mController->GetMaximumNumberOfCharacters();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::SELECTED_TEXT:
-      {
-        value = impl.mController->GetSelectedText();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
-      {
-        Uint32Pair range = impl.GetTextSelectionRange();
-        value            = static_cast<int>(range.first);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
-      {
-        Uint32Pair range = impl.GetTextSelectionRange();
-        value            = static_cast<int>(range.second);
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
-      {
-        value = impl.IsEditable();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
-      {
-        value = impl.GetHorizontalScrollPosition();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
-      {
-        value = impl.GetVerticalScrollPosition();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
-      {
-        value = impl.mController->GetFontSizeScale();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
-      {
-        value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::GRAB_HANDLE_COLOR:
-      {
-        value = impl.mDecorator->GetHandleColor();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
-      {
-        value = impl.mController->IsGrabHandlePopupEnabled();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
-      {
-        Property::Map map;
-        impl.mInputMethodOptions.RetrieveProperty(map);
-        value = map;
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
-      {
-        Property::Map map;
-        impl.mController->GetInputFilterOption(map);
-        value = map;
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ELLIPSIS:
-      {
-        value = impl.mController->IsTextElideEnabled();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
-      {
-        value = impl.mController->GetEllipsisPosition();
-        break;
-      }
-      case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE:
-      {
-        value = impl.mController->GetDefaultLineSize();
-        break;
-      }
-    } //switch
+    value = PropertyHandler::GetProperty(textEditor, index);
   }
-
   return value;
 }
 
@@ -1550,13 +572,13 @@ void TextEditor::OnInitialize()
 
 void TextEditor::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange\n");
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnStyleChange\n");
 
   switch(change)
   {
     case StyleChange::DEFAULT_FONT_CHANGE:
     {
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n");
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n");
       const std::string& newFont = GetImpl(styleManager).GetDefaultFontFamily();
       // Property system did not set the font so should update it.
       mController->UpdateAfterFontChange(newFont);
@@ -1610,7 +632,7 @@ void TextEditor::ResizeActor(Actor& actor, const Vector2& size)
 
 void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor OnRelayout\n");
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor OnRelayout\n");
 
   Actor self = Self();
 
@@ -1649,7 +671,7 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
      !mRenderer)
   {
-    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnRelayout %p Displaying new contents\n", mController.Get());
+    DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnRelayout %p Displaying new contents\n", mController.Get());
 
     if(mDecorator &&
        (Text::Controller::NONE_UPDATED != (Text::Controller::DECORATOR_UPDATED & updateTextType)))
@@ -1702,100 +724,9 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
 
 void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
 {
-  Actor renderableActor;
-
-  if(Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType))
-  {
-    if(mRenderer)
-    {
-      Dali::Toolkit::TextEditor handle = Dali::Toolkit::TextEditor(GetOwner());
-
-      renderableActor = mRenderer->Render(mController->GetView(),
-                                          handle,
-                                          Property::INVALID_INDEX, // Animatable property not supported
-                                          mAlignmentOffset,
-                                          DepthIndex::CONTENT);
-    }
-
-    if(renderableActor != mRenderableActor)
-    {
-      UnparentAndReset(mBackgroundActor);
-      UnparentAndReset(mRenderableActor);
-      mRenderableActor = renderableActor;
-
-      if(mRenderableActor)
-      {
-        mBackgroundActor = mController->CreateBackgroundActor();
-      }
-    }
-  }
-
+  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, updateTextType);
   if(mRenderableActor)
   {
-    const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
-
-    float renderableActorPositionX, renderableActorPositionY;
-
-    if(mStencil)
-    {
-      renderableActorPositionX = scrollOffset.x + mAlignmentOffset;
-      renderableActorPositionY = scrollOffset.y;
-    }
-    else
-    {
-      Extents padding;
-      padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
-
-      // Support Right-To-Left of padding
-      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
-      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
-      {
-        std::swap(padding.start, padding.end);
-      }
-
-      renderableActorPositionX = scrollOffset.x + mAlignmentOffset + padding.start;
-      renderableActorPositionY = scrollOffset.y + padding.top;
-    }
-
-    mRenderableActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY));
-    // Make sure the actors are parented correctly with/without clipping
-    Actor self = mStencil ? mStencil : Self();
-
-    Actor highlightActor;
-
-    for(std::vector<Actor>::iterator it    = mClippingDecorationActors.begin(),
-                                     endIt = mClippingDecorationActors.end();
-        it != endIt;
-        ++it)
-    {
-      self.Add(*it);
-      it->LowerToBottom();
-
-      if(it->GetProperty<std::string>(Dali::Actor::Property::NAME) == "HighlightActor")
-      {
-        highlightActor = *it;
-      }
-    }
-    mClippingDecorationActors.clear();
-
-    self.Add(mRenderableActor);
-
-    if(mBackgroundActor)
-    {
-      if(mDecorator && mDecorator->IsHighlightVisible())
-      {
-        self.Add(mBackgroundActor);
-        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY)); // In text field's coords.
-        mBackgroundActor.LowerBelow(highlightActor);
-      }
-      else
-      {
-        mRenderableActor.Add(mBackgroundActor);
-        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); // In renderable actor's coords.
-        mBackgroundActor.LowerToBottom();
-      }
-    }
-
     ApplyScrollPosition();
   }
   UpdateScrollBar();
@@ -1803,7 +734,7 @@ void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
 
 void TextEditor::OnKeyInputFocusGained()
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get());
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get());
   if(mInputMethodContext && IsEditable())
   {
     // All input panel properties, such as layout, return key type, and input hint, should be set before input panel activates (or shows).
@@ -1834,7 +765,7 @@ void TextEditor::OnKeyInputFocusGained()
 
 void TextEditor::OnKeyInputFocusLost()
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor:OnKeyInputFocusLost %p\n", mController.Get());
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor:OnKeyInputFocusLost %p\n", mController.Get());
   if(mInputMethodContext)
   {
     mInputMethodContext.StatusChangedSignal().Disconnect(this, &TextEditor::KeyboardStatusChanged);
@@ -1867,7 +798,7 @@ bool TextEditor::OnAccessibilityActivated()
 
 void TextEditor::OnTap(const TapGesture& gesture)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get());
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get());
   if(mInputMethodContext && IsEditable())
   {
     mInputMethodContext.Activate();
@@ -1903,7 +834,7 @@ void TextEditor::OnLongPress(const LongPressGesture& gesture)
 
 bool TextEditor::OnKeyEvent(const KeyEvent& event)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnKeyEvent %p keyCode %d\n", mController.Get(), event.GetKeyCode());
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnKeyEvent %p keyCode %d\n", mController.Get(), event.GetKeyCode());
 
   if(Dali::DALI_KEY_ESCAPE == event.GetKeyCode() && mController->ShouldClearFocusOnEscape())
   {
@@ -1982,55 +913,7 @@ void TextEditor::MaxLengthReached()
 void TextEditor::InputStyleChanged(Text::InputStyle::Mask inputStyleMask)
 {
   Dali::Toolkit::TextEditor handle(GetOwner());
-
-  Toolkit::TextEditor::InputStyle::Mask editorInputStyleMask = Toolkit::TextEditor::InputStyle::NONE;
-
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_COLOR))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::COLOR);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_FAMILY))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_FAMILY);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_POINT_SIZE))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::POINT_SIZE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WEIGHT))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WIDTH))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_SLANT))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_LINE_SPACING))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::LINE_SPACING);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_UNDERLINE))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::UNDERLINE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_SHADOW))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::SHADOW);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_EMBOSS))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::EMBOSS);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_OUTLINE))
-  {
-    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>(editorInputStyleMask | Toolkit::TextEditor::InputStyle::OUTLINE);
-  }
-
-  mInputStyleChangedSignal.Emit(handle, editorInputStyleMask);
+  mInputStyleChangedSignal.Emit(handle, ConvertInputStyle(inputStyleMask));
 }
 
 void TextEditor::AnchorClicked(const std::string& href)
@@ -2248,7 +1131,7 @@ void TextEditor::OnSceneConnect(Dali::Actor actor)
 
 InputMethodContext::CallbackData TextEditor::OnInputMethodContextEvent(Dali::InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName);
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName);
   return mController->OnInputMethodContextEvent(inputMethodContext, inputMethodContextEvent);
 }
 
@@ -2257,8 +1140,9 @@ void TextEditor::GetHandleImagePropertyValue(Property::Value& value, Text::Handl
   if(mDecorator)
   {
     Property::Map map;
-    map[IMAGE_MAP_FILENAME_STRING] = mDecorator->GetHandleImage(handleType, handleImageType);
-    value                          = map;
+    map[TextEditor::PropertyHandler::IMAGE_MAP_FILENAME_STRING] = mDecorator->GetHandleImage(handleType, handleImageType);
+
+    value = map;
   }
 }
 
@@ -2269,7 +1153,7 @@ void TextEditor::OnClipboardTextSelected(ClipboardEventNotifier& clipboard)
 
 void TextEditor::KeyboardStatusChanged(bool keyboardShown)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextEditor::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown);
+  DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown);
 
   // Just hide the grab handle when keyboard is hidden.
   if(!keyboardShown)
index bc28781..8c5d7be 100644 (file)
@@ -522,6 +522,8 @@ private: // Data
   uint32_t mOldSelectionStart;
   uint32_t mOldSelectionEnd;
 
+  struct PropertyHandler;
+
   /**
    * @brief This structure is to connect TextEditor with Accessible functions.
    */
diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-property-handler.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-property-handler.cpp
new file mode 100644 (file)
index 0000000..62dfbda
--- /dev/null
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h>
+
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali/integration-api/debug.h>
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gTextEditorLogFilter;
+#endif
+
+namespace Dali::Toolkit::Internal
+{
+const char* const TextEditor::PropertyHandler::IMAGE_MAP_FILENAME_STRING{"filename"};
+
+/// Retrieves a filename from a value that is a Property::Map
+std::string TextEditor::PropertyHandler::GetImageFileNameFromPropertyValue(const Property::Value& value)
+{
+  std::string          filename;
+  const Property::Map* map = value.GetMap();
+  if(map)
+  {
+    const Property::Value* filenameValue = map->Find(TextEditor::PropertyHandler::IMAGE_MAP_FILENAME_STRING);
+    if(filenameValue)
+    {
+      filenameValue->Get(filename);
+    }
+  }
+  return filename;
+}
+
+void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Property::Index index, const Property::Value& value)
+{
+  TextEditor& impl(GetImpl(textEditor));
+  DALI_ASSERT_DEBUG(impl.mController && "No text controller");
+  DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
+
+  switch(index)
+  {
+    case Toolkit::DevelTextEditor::Property::RENDERING_BACKEND:
+    {
+      int backend = value.Get<int>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend);
+
+      if(impl.mRenderingBackend != backend)
+      {
+        impl.mRenderingBackend = backend;
+        impl.mRenderer.Reset();
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::TEXT:
+    {
+      const std::string& text = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p TEXT %s\n", impl.mController.Get(), text.c_str());
+
+      impl.mController->SetText(text);
+      break;
+    }
+    case Toolkit::TextEditor::Property::TEXT_COLOR:
+    {
+      const Vector4& textColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
+
+      if(impl.mController->GetDefaultColor() != textColor)
+      {
+        impl.mController->SetDefaultColor(textColor);
+        impl.mController->SetInputColor(textColor);
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::FONT_FAMILY:
+    {
+      const std::string& fontFamily = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
+      impl.mController->SetDefaultFontFamily(fontFamily);
+      break;
+    }
+    case Toolkit::TextEditor::Property::FONT_STYLE:
+    {
+      SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::POINT_SIZE:
+    {
+      const float pointSize = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p POINT_SIZE %f\n", impl.mController.Get(), pointSize);
+
+      if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize))
+      {
+        impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE);
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
+    {
+      Text::HorizontalAlignment::Type alignment(static_cast<Text::HorizontalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Text::GetHorizontalAlignmentEnumeration(value, alignment))
+      {
+        DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
+        impl.mController->SetHorizontalAlignment(alignment);
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
+    {
+      const float threshold = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold);
+
+      impl.mDecorator->SetScrollThreshold(threshold);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_SPEED:
+    {
+      const float speed = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p SCROLL_SPEED %f\n", impl.mController.Get(), speed);
+
+      impl.mDecorator->SetScrollSpeed(speed);
+      break;
+    }
+    case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
+    {
+      const Vector4& color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetCursorColor(Toolkit::Text::PRIMARY_CURSOR, color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
+    {
+      const Vector4& color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetCursorColor(Toolkit::Text::SECONDARY_CURSOR, color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
+    {
+      const bool enable = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable);
+
+      impl.mController->SetEnableCursorBlink(enable);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
+    {
+      const float interval = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval);
+
+      impl.mDecorator->SetCursorBlinkInterval(interval);
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
+    {
+      const float duration = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration);
+
+      impl.mDecorator->SetCursorBlinkDuration(duration);
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_WIDTH:
+    {
+      const int width = value.Get<int>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p CURSOR_WIDTH %d\n", impl.mController.Get(), width);
+
+      impl.mDecorator->SetCursorWidth(width);
+      impl.mController->GetLayoutEngine().SetCursorWidth(width);
+      break;
+    }
+    case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
+    {
+      const std::string imageFileName = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
+
+      if(imageFileName.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::GRAB_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, imageFileName);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
+    {
+      const std::string imageFileName = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
+
+      if(imageFileName.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::GRAB_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, imageFileName);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE_MARKER,
+                                        Toolkit::Text::HANDLE_IMAGE_RELEASED,
+                                        filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE_MARKER,
+                                        Toolkit::Text::HANDLE_IMAGE_RELEASED,
+                                        filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
+    {
+      const Vector4 color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetHighlightColor(color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
+    {
+      const Rect<int>& box = value.Get<Rect<int> >();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height);
+
+      impl.mDecorator->SetBoundingBox(box);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_MARKUP:
+    {
+      const bool enableMarkup = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
+
+      impl.mController->SetMarkupProcessorEnabled(enableMarkup);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_COLOR:
+    {
+      const Vector4& inputColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a);
+
+      impl.mController->SetInputColor(inputColor);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
+    {
+      const std::string& fontFamily = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
+      impl.mController->SetInputFontFamily(fontFamily);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
+    {
+      SetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
+    {
+      const float pointSize = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize);
+      impl.mController->SetInputFontPointSize(pointSize);
+      break;
+    }
+    case Toolkit::TextEditor::Property::LINE_SPACING:
+    {
+      const float lineSpacing = value.Get<float>();
+      impl.mController->SetDefaultLineSpacing(lineSpacing);
+      impl.mRenderer.Reset();
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
+    {
+      const float lineSpacing = value.Get<float>();
+      impl.mController->SetInputLineSpacing(lineSpacing);
+      impl.mRenderer.Reset();
+      break;
+    }
+    case Toolkit::TextEditor::Property::UNDERLINE:
+    {
+      const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
+    {
+      const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SHADOW:
+    {
+      const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_SHADOW:
+    {
+      const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::EMBOSS:
+    {
+      const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_EMBOSS:
+    {
+      const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::OUTLINE:
+    {
+      const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_OUTLINE:
+    {
+      const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
+    {
+      const bool enable = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor SMOOTH_SCROLL %d\n", enable);
+
+      impl.mScrollAnimationEnabled = enable;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
+    {
+      const float duration = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor SMOOTH_SCROLL_DURATION %f\n", duration);
+
+      impl.mScrollAnimationDuration = duration;
+      if(impl.mTextVerticalScroller)
+      {
+        impl.mTextVerticalScroller->SetDuration(duration);
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
+    {
+      const bool enable = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor SHOW_SCROLL_BAR %d\n", enable);
+
+      impl.mScrollBarEnabled = enable;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
+    {
+      const float duration = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor SCROLL_BAR_SHOW_DURATION %f\n", duration);
+
+      impl.mAnimationPeriod.delaySeconds = duration;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
+    {
+      const float duration = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor SCROLL_BAR_FADE_DURATION %f\n", duration);
+
+      impl.mAnimationPeriod.durationSeconds = duration;
+      break;
+    }
+    case Toolkit::TextEditor::Property::PIXEL_SIZE:
+    {
+      const float pixelSize = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize);
+
+      if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize))
+      {
+        impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
+    {
+      const std::string& text = value.Get<std::string>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor::OnPropertySet %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str());
+
+      impl.mController->SetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_INACTIVE, text);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
+    {
+      const Vector4& textColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
+
+      if(impl.mController->GetPlaceholderTextColor() != textColor)
+      {
+        impl.mController->SetPlaceholderTextColor(textColor);
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_SELECTION:
+    {
+      const bool enableSelection = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection);
+      impl.mController->SetSelectionEnabled(enableSelection);
+      break;
+    }
+    case Toolkit::TextEditor::Property::PLACEHOLDER:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mController->SetPlaceholderProperty(*map);
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
+    {
+      Text::LineWrap::Mode lineWrapMode(static_cast<Text::LineWrap::Mode>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Toolkit::Text::GetLineWrapModeEnumeration(value, lineWrapMode))
+      {
+        DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode);
+        impl.mController->SetLineWrapMode(lineWrapMode);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
+    {
+      const bool shiftSelection = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection);
+
+      impl.mController->SetShiftSelectionEnabled(shiftSelection);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
+    {
+      const bool grabHandleEnabled = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled);
+
+      impl.mController->SetGrabHandleEnabled(grabHandleEnabled);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+    {
+      impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MAX_LENGTH:
+    {
+      const int max = value.Get<int>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p MAX_LENGTH %d\n", impl.mController.Get(), max);
+
+      impl.mController->SetMaximumNumberOfCharacters(max);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
+    {
+      uint32_t start = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start);
+      impl.SetTextSelectionRange(&start, nullptr);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
+    {
+      uint32_t end = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end);
+      impl.SetTextSelectionRange(nullptr, &end);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
+    {
+      const bool editable = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_EDITING %d\n", impl.mController.Get(), editable);
+      impl.SetEditable(editable);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
+    {
+      float horizontalScroll = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p HORIZONTAL_SCROLL_POSITION %d\n", impl.mController.Get(), horizontalScroll);
+      if(horizontalScroll >= 0.0f)
+      {
+        impl.ScrollBy(Vector2(horizontalScroll - impl.GetHorizontalScrollPosition(), 0));
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
+    {
+      float verticalScroll = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p VERTICAL_SCROLL_POSITION %d\n", impl.mController.Get(), verticalScroll);
+      if(verticalScroll >= 0.0f)
+      {
+        impl.ScrollBy(Vector2(0, verticalScroll - impl.GetVerticalScrollPosition()));
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
+    {
+      const float scale = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale);
+
+      if(!Equals(impl.mController->GetFontSizeScale(), scale))
+      {
+        impl.mController->SetFontSizeScale(scale);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
+    {
+      uint32_t position = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position);
+      if(impl.mController->SetPrimaryCursorPosition(position, impl.HasKeyInputFocus()))
+      {
+        impl.SetKeyInputFocus();
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::GRAB_HANDLE_COLOR:
+    {
+      const Vector4 color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p GRAB_HANDLE_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetHandleColor(color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+    {
+      const bool grabHandlePopupEnabled = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
+
+      impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mInputMethodOptions.ApplyProperty(*map);
+      }
+      impl.mController->SetInputModePassword(impl.mInputMethodOptions.IsPassword());
+
+      Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+      if(control == textEditor)
+      {
+        impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mController->SetInputFilterOption(*map);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ELLIPSIS:
+    {
+      const bool ellipsis = value.Get<bool>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
+
+      impl.mController->SetTextElideEnabled(ellipsis);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
+    {
+      DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Text::GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+      {
+        DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+        impl.mController->SetEllipsisPosition(ellipsisPositionType);
+      }
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE:
+    {
+      const float minLineSize = value.Get<float>();
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::Verbose, "TextEditor %p MIN_LINE_SIZE %f\n", impl.mController.Get(), minLineSize);
+
+      impl.mController->SetDefaultLineSize(minLineSize);
+      impl.mRenderer.Reset();
+      break;
+    }
+  }
+}
+
+Property::Value TextEditor::PropertyHandler::GetProperty(Toolkit::TextEditor textEditor, Property::Index index)
+{
+  Property::Value value;
+  TextEditor&     impl(GetImpl(textEditor));
+  DALI_ASSERT_DEBUG(impl.mController && "No text controller");
+  DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
+
+  switch(index)
+  {
+    case Toolkit::DevelTextEditor::Property::RENDERING_BACKEND:
+    {
+      value = impl.mRenderingBackend;
+      break;
+    }
+    case Toolkit::TextEditor::Property::TEXT:
+    {
+      std::string text;
+      impl.mController->GetText(text);
+      DALI_LOG_INFO(gTextEditorLogFilter, Debug::General, "TextEditor %p returning text: %s\n", impl.mController.Get(), text.c_str());
+      value = text;
+      break;
+    }
+    case Toolkit::TextEditor::Property::TEXT_COLOR:
+    {
+      value = impl.mController->GetDefaultColor();
+      break;
+    }
+    case Toolkit::TextEditor::Property::FONT_FAMILY:
+    {
+      value = impl.mController->GetDefaultFontFamily();
+      break;
+    }
+    case Toolkit::TextEditor::Property::FONT_STYLE:
+    {
+      GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::POINT_SIZE:
+    {
+      value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE);
+      break;
+    }
+    case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
+    {
+      const char* name = Text::GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment());
+      if(name)
+      {
+        value = std::string(name);
+      }
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
+    {
+      value = impl.mDecorator->GetScrollThreshold();
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_SPEED:
+    {
+      value = impl.mDecorator->GetScrollSpeed();
+      break;
+    }
+    case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
+    {
+      value = impl.mDecorator->GetColor(Text::PRIMARY_CURSOR);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
+    {
+      value = impl.mDecorator->GetColor(Text::SECONDARY_CURSOR);
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
+    {
+      value = impl.mController->GetEnableCursorBlink();
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
+    {
+      value = impl.mDecorator->GetCursorBlinkInterval();
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
+    {
+      value = impl.mDecorator->GetCursorBlinkDuration();
+      break;
+    }
+    case Toolkit::TextEditor::Property::CURSOR_WIDTH:
+    {
+      value = impl.mDecorator->GetCursorWidth();
+      break;
+    }
+    case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
+    {
+      value = impl.mDecorator->GetHandleImage(Text::GRAB_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
+    {
+      value = impl.mDecorator->GetHandleImage(Text::GRAB_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE_MARKER, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE_MARKER, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
+    {
+      value = impl.mDecorator->GetHighlightColor();
+      break;
+    }
+    case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
+    {
+      Rect<int> boundingBox;
+      impl.mDecorator->GetBoundingBox(boundingBox);
+      value = boundingBox;
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_MARKUP:
+    {
+      value = impl.mController->IsMarkupProcessorEnabled();
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_COLOR:
+    {
+      value = impl.mController->GetInputColor();
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
+    {
+      value = impl.mController->GetInputFontFamily();
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
+    {
+      GetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
+    {
+      value = impl.mController->GetInputFontPointSize();
+      break;
+    }
+    case Toolkit::TextEditor::Property::LINE_SPACING:
+    {
+      value = impl.mController->GetDefaultLineSpacing();
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
+    {
+      value = impl.mController->GetInputLineSpacing();
+      break;
+    }
+    case Toolkit::TextEditor::Property::UNDERLINE:
+    {
+      GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
+    {
+      GetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SHADOW:
+    {
+      GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_SHADOW:
+    {
+      GetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::EMBOSS:
+    {
+      GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_EMBOSS:
+    {
+      GetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::OUTLINE:
+    {
+      GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::INPUT_OUTLINE:
+    {
+      GetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
+    {
+      value = impl.mScrollAnimationEnabled;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
+    {
+      value = impl.mScrollAnimationDuration;
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
+    {
+      value = impl.mScrollBarEnabled;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
+    {
+      value = impl.mAnimationPeriod.delaySeconds;
+      break;
+    }
+    case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
+    {
+      value = impl.mAnimationPeriod.durationSeconds;
+      break;
+    }
+    case Toolkit::TextEditor::Property::PIXEL_SIZE:
+    {
+      value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE);
+      break;
+    }
+    case Toolkit::TextEditor::Property::LINE_COUNT:
+    {
+      float width = textEditor.GetProperty(Actor::Property::SIZE_WIDTH).Get<float>();
+      value       = impl.mController->GetLineCount(width);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
+    {
+      std::string text;
+      impl.mController->GetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_INACTIVE, text);
+      value = text;
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
+    {
+      value = impl.mController->GetPlaceholderTextColor();
+      break;
+    }
+    case Toolkit::TextEditor::Property::ENABLE_SELECTION:
+    {
+      value = impl.mController->IsSelectionEnabled();
+      break;
+    }
+    case Toolkit::TextEditor::Property::PLACEHOLDER:
+    {
+      Property::Map map;
+      impl.mController->GetPlaceholderProperty(map);
+      value = map;
+      break;
+    }
+    case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
+    {
+      value = impl.mController->GetLineWrapMode();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
+    {
+      value = impl.mController->IsShiftSelectionEnabled();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
+    {
+      value = impl.mController->IsGrabHandleEnabled();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+    {
+      value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MAX_LENGTH:
+    {
+      value = impl.mController->GetMaximumNumberOfCharacters();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::SELECTED_TEXT:
+    {
+      value = impl.mController->GetSelectedText();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_START:
+    {
+      Uint32Pair range = impl.GetTextSelectionRange();
+      value            = static_cast<int>(range.first);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::SELECTED_TEXT_END:
+    {
+      Uint32Pair range = impl.GetTextSelectionRange();
+      value            = static_cast<int>(range.second);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_EDITING:
+    {
+      value = impl.IsEditable();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::HORIZONTAL_SCROLL_POSITION:
+    {
+      value = impl.GetHorizontalScrollPosition();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::VERTICAL_SCROLL_POSITION:
+    {
+      value = impl.GetVerticalScrollPosition();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::FONT_SIZE_SCALE:
+    {
+      value = impl.mController->GetFontSizeScale();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::PRIMARY_CURSOR_POSITION:
+    {
+      value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::GRAB_HANDLE_COLOR:
+    {
+      value = impl.mDecorator->GetHandleColor();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+    {
+      value = impl.mController->IsGrabHandlePopupEnabled();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
+    {
+      Property::Map map;
+      impl.mInputMethodOptions.RetrieveProperty(map);
+      value = map;
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::INPUT_FILTER:
+    {
+      Property::Map map;
+      impl.mController->GetInputFilterOption(map);
+      value = map;
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ELLIPSIS:
+    {
+      value = impl.mController->IsTextElideEnabled();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
+    {
+      value = impl.mController->GetEllipsisPosition();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::MIN_LINE_SIZE:
+    {
+      value = impl.mController->GetDefaultLineSize();
+      break;
+    }
+  } //switch
+  return value;
+}
+
+} // namespace Dali::Toolkit::Internal
diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h b/dali-toolkit/internal/controls/text-controls/text-editor-property-handler.h
new file mode 100644 (file)
index 0000000..2664f4d
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_PROPERTY_HANDLER_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_PROPERTY_HANDLER_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
+
+namespace Dali::Toolkit::Internal
+{
+/**
+ * Class to manage properties for the TextEditor
+ */
+struct TextEditor::PropertyHandler
+{
+  static const char* const IMAGE_MAP_FILENAME_STRING; //<<< "filename" key for image map
+
+  /**
+   * Set properties on the text editor / controller / decorator
+   *
+   * @param[in] textEditor The handle for the text editor
+   * @param[in] index The property index of the property to set
+   * @param[in] value The value to set
+   */
+  static void SetProperty(Toolkit::TextEditor textEditor, Property::Index index, const Property::Value& value);
+
+  /**
+   * Get properties from the text editor / controller / decorator
+   *
+   * @param[in] textEditor The handle for the text editor
+   * @param[in] index The property index of the property to set
+   * @return the value
+   */
+  static Property::Value GetProperty(Toolkit::TextEditor textEditor, Property::Index index);
+
+private:
+  /**
+   * Method to extract "filename" value from a Property::Map
+   *
+   * @param[in] The property value containing the Property::Map
+   * @return The resulting "filename" value if present
+   */
+  static std::string GetImageFileNameFromPropertyValue(const Property::Value& value);
+};
+
+} // namespace Dali::Toolkit::Internal
+
+#endif //DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_PROPERTY_HANDLER_H
index 32beca1..fe01e46 100644 (file)
 #include <dali/devel-api/common/stage.h>
 #include <dali/devel-api/object/property-helper-devel.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/layer.h>
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <cstring>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 #include <dali-toolkit/devel-api/text/rendering-backend.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
+#include <dali-toolkit/internal/controls/text-controls/text-field-property-handler.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/text/rendering/text-backend.h>
 #include <dali-toolkit/internal/text/text-effects-style.h>
 
 using namespace Dali::Toolkit::Text;
 
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gTextFieldLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
+#endif
+
 namespace Dali
 {
 namespace Toolkit
@@ -56,10 +62,6 @@ namespace Internal
 {
 namespace // unnamed namespace
 {
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
-#endif
-
 const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT_RENDERING_BACKEND;
 } // unnamed namespace
 
@@ -152,22 +154,51 @@ DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "selectionCleared",      SIGNAL_SEL
 DALI_TYPE_REGISTRATION_END()
 // clang-format on
 
-const char* const IMAGE_MAP_FILENAME_STRING = "filename";
-
-/// Retrieves a filename from a value that is a Property::Map
-std::string GetImageFileNameFromPropertyValue(const Property::Value& value)
+Toolkit::TextField::InputStyle::Mask ConvertInputStyle(Text::InputStyle::Mask inputStyleMask)
 {
-  std::string          filename;
-  const Property::Map* map = value.GetMap();
-  if(map)
+  Toolkit::TextField::InputStyle::Mask fieldInputStyleMask = Toolkit::TextField::InputStyle::NONE;
+
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_COLOR))
   {
-    const Property::Value* filenameValue = map->Find(IMAGE_MAP_FILENAME_STRING);
-    if(filenameValue)
-    {
-      filenameValue->Get(filename);
-    }
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::COLOR);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_FAMILY))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_FAMILY);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_POINT_SIZE))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::POINT_SIZE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WEIGHT))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WIDTH))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_SLANT))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_UNDERLINE))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::UNDERLINE);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_SHADOW))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::SHADOW);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_EMBOSS))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::EMBOSS);
+  }
+  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_OUTLINE))
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::OUTLINE);
   }
-  return filename;
+  return fieldInputStyleMask;
 }
 
 } // namespace
@@ -191,606 +222,12 @@ void TextField::SetProperty(BaseObject* object, Property::Index index, const Pro
 {
   Toolkit::TextField textField = Toolkit::TextField::DownCast(Dali::BaseHandle(object));
 
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField SetProperty\n");
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField SetProperty\n");
 
   if(textField)
   {
-    TextField& impl(GetImpl(textField));
-    DALI_ASSERT_DEBUG(impl.mController && "No text contoller");
-    DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
-
-    switch(index)
-    {
-      case Toolkit::DevelTextField::Property::RENDERING_BACKEND:
-      {
-        int backend = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend);
-
-#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
-        if(DevelText::RENDERING_VECTOR_BASED == backend)
-        {
-          backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
-        }
-#endif
-        if(impl.mRenderingBackend != backend)
-        {
-          impl.mRenderingBackend = backend;
-          impl.mRenderer.Reset();
-
-          // When using the vector-based rendering, the size of the GLyphs are different
-          TextAbstraction::GlyphType glyphType = (DevelText::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
-          impl.mController->SetGlyphType(glyphType);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::TEXT:
-      {
-        const std::string& text = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p TEXT %s\n", impl.mController.Get(), text.c_str());
-
-        impl.mController->SetText(text);
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
-      {
-        const std::string& text = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str());
-
-        impl.mController->SetPlaceholderText(Controller::PLACEHOLDER_TYPE_INACTIVE, text);
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
-      {
-        const std::string& text = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_FOCUSED %s\n", impl.mController.Get(), text.c_str());
-
-        impl.mController->SetPlaceholderText(Controller::PLACEHOLDER_TYPE_ACTIVE, text);
-        break;
-      }
-      case Toolkit::TextField::Property::FONT_FAMILY:
-      {
-        const std::string& fontFamily = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
-        impl.mController->SetDefaultFontFamily(fontFamily);
-        break;
-      }
-      case Toolkit::TextField::Property::FONT_STYLE:
-      {
-        SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::POINT_SIZE:
-      {
-        const float pointSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p POINT_SIZE %f\n", impl.mController.Get(), pointSize);
-
-        if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize))
-        {
-          impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::MAX_LENGTH:
-      {
-        const int max = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p MAX_LENGTH %d\n", impl.mController.Get(), max);
-
-        impl.mController->SetMaximumNumberOfCharacters(max);
-        break;
-      }
-      case Toolkit::TextField::Property::EXCEED_POLICY:
-      {
-        impl.mExceedPolicy = value.Get<int>();
-
-        if(Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == impl.mExceedPolicy)
-        {
-          impl.EnableClipping();
-        }
-        else
-        {
-          UnparentAndReset(impl.mStencil);
-        }
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
-      {
-        Text::HorizontalAlignment::Type alignment(static_cast<Text::HorizontalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(GetHorizontalAlignmentEnumeration(value, alignment))
-        {
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
-          impl.mController->SetHorizontalAlignment(alignment);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
-      {
-        Toolkit::Text::VerticalAlignment::Type alignment(static_cast<Text::VerticalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(GetVerticalAlignmentEnumeration(value, alignment))
-        {
-          impl.mController->SetVerticalAlignment(alignment);
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::TEXT_COLOR:
-      {
-        const Vector4& textColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
-
-        if(impl.mController->GetDefaultColor() != textColor)
-        {
-          impl.mController->SetDefaultColor(textColor);
-          impl.mController->SetInputColor(textColor);
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
-      {
-        const Vector4& textColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
-
-        if(impl.mController->GetPlaceholderTextColor() != textColor)
-        {
-          impl.mController->SetPlaceholderTextColor(textColor);
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
-      {
-        const Vector4& color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetCursorColor(PRIMARY_CURSOR, color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
-      {
-        const Vector4& color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetCursorColor(SECONDARY_CURSOR, color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
-      {
-        const bool enable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable);
-
-        impl.mController->SetEnableCursorBlink(enable);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
-      {
-        const float interval = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval);
-
-        impl.mDecorator->SetCursorBlinkInterval(interval);
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
-      {
-        const float duration = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration);
-
-        impl.mDecorator->SetCursorBlinkDuration(duration);
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_WIDTH:
-      {
-        const int width = value.Get<int>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p CURSOR_WIDTH %d\n", impl.mController.Get(), width);
-
-        impl.mDecorator->SetCursorWidth(width);
-        impl.mController->GetLayoutEngine().SetCursorWidth(width);
-        break;
-      }
-      case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
-      {
-        const std::string imageFileName = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
-
-        if(imageFileName.size())
-        {
-          impl.mDecorator->SetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_RELEASED, imageFileName);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
-      {
-        const std::string imageFileName = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
-
-        if(imageFileName.size())
-        {
-          impl.mDecorator->SetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_PRESSED, imageFileName);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SCROLL_THRESHOLD:
-      {
-        const float threshold = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold);
-
-        impl.mDecorator->SetScrollThreshold(threshold);
-        break;
-      }
-      case Toolkit::TextField::Property::SCROLL_SPEED:
-      {
-        const float speed = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField %p SCROLL_SPEED %f\n", impl.mController.Get(), speed);
-
-        impl.mDecorator->SetScrollSpeed(speed);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
-      {
-        const std::string filename = GetImageFileNameFromPropertyValue(value);
-
-        if(filename.size())
-        {
-          impl.mDecorator->SetHandleImage(RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, filename);
-          impl.RequestTextRelayout();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
-      {
-        const Vector4 color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetHighlightColor(color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
-      {
-        const Rect<int> box = value.Get<Rect<int> >();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height);
-
-        impl.mDecorator->SetBoundingBox(box);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mInputMethodOptions.ApplyProperty(*map);
-        }
-        impl.mController->SetInputModePassword(impl.mInputMethodOptions.IsPassword());
-
-        Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
-        if(control == textField)
-        {
-          impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_COLOR:
-      {
-        const Vector4 inputColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a);
-
-        impl.mController->SetInputColor(inputColor);
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_MARKUP:
-      {
-        const bool enableMarkup = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
-
-        impl.mController->SetMarkupProcessorEnabled(enableMarkup);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
-      {
-        const std::string& fontFamily = value.Get<std::string>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
-        impl.mController->SetInputFontFamily(fontFamily);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_FONT_STYLE:
-      {
-        SetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_POINT_SIZE:
-      {
-        const float pointSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize);
-        impl.mController->SetInputFontPointSize(pointSize);
-        break;
-      }
-      case Toolkit::TextField::Property::UNDERLINE:
-      {
-        const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_UNDERLINE:
-      {
-        const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::SHADOW:
-      {
-        const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_SHADOW:
-      {
-        const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::EMBOSS:
-      {
-        const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_EMBOSS:
-      {
-        const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::OUTLINE:
-      {
-        const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_OUTLINE:
-      {
-        const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        if(update)
-        {
-          impl.mRenderer.Reset();
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mController->SetHiddenInputOption(*map);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::PIXEL_SIZE:
-      {
-        const float pixelSize = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize);
-
-        if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize))
-        {
-          impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_SELECTION:
-      {
-        const bool enableSelection = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection);
-        impl.mController->SetSelectionEnabled(enableSelection);
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mController->SetPlaceholderProperty(*map);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::ELLIPSIS:
-      {
-        const bool ellipsis = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
-
-        impl.mController->SetTextElideEnabled(ellipsis);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
-      {
-        const bool shiftSelection = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection);
-
-        impl.mController->SetShiftSelectionEnabled(shiftSelection);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
-      {
-        const bool grabHandleEnabled = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled);
-
-        impl.mController->SetGrabHandleEnabled(grabHandleEnabled);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
-      {
-        impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
-      {
-        const bool grabHandlePopupEnabled = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
-
-        impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::BACKGROUND:
-      {
-        const Vector4 backgroundColor = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p BACKGROUND %f,%f,%f,%f\n", impl.mController.Get(), backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a);
-
-        impl.mController->SetBackgroundEnabled(true);
-        impl.mController->SetBackgroundColor(backgroundColor);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::SELECTED_TEXT_START:
-      {
-        uint32_t start = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start);
-        impl.SetTextSelectionRange(&start, nullptr);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::SELECTED_TEXT_END:
-      {
-        uint32_t end = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end);
-        impl.SetTextSelectionRange(nullptr, &end);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_EDITING:
-      {
-        const bool editable = value.Get<bool>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_EDITING %d\n", impl.mController.Get(), editable);
-        impl.SetEditable(editable);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::FONT_SIZE_SCALE:
-      {
-        const float scale = value.Get<float>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale);
-
-        if(!Equals(impl.mController->GetFontSizeScale(), scale))
-        {
-          impl.mController->SetFontSizeScale(scale);
-        }
-        break;
-      }
-      case Toolkit::DevelTextField::Property::PRIMARY_CURSOR_POSITION:
-      {
-        uint32_t position = static_cast<uint32_t>(value.Get<int>());
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position);
-        if(impl.mController->SetPrimaryCursorPosition(position, impl.HasKeyInputFocus()))
-        {
-          impl.SetKeyInputFocus();
-        }
-        break;
-      }
-      case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
-      {
-        const Vector4 color = value.Get<Vector4>();
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p GRAB_HANDLE_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
-
-        impl.mDecorator->SetHandleColor(color);
-        impl.RequestTextRelayout();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::INPUT_FILTER:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          impl.mController->SetInputFilterOption(*map);
-        }
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
-      {
-        DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
-        if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
-        {
-          DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
-          impl.mController->SetEllipsisPosition(ellipsisPositionType);
-        }
-        break;
-      }
-    } // switch
-  }   // textfield
+    PropertyHandler::SetProperty(textField, index, value);
+  }
 }
 
 Property::Value TextField::GetProperty(BaseObject* object, Property::Index index)
@@ -801,362 +238,7 @@ Property::Value TextField::GetProperty(BaseObject* object, Property::Index index
 
   if(textField)
   {
-    TextField& impl(GetImpl(textField));
-    DALI_ASSERT_DEBUG(impl.mController && "No text contoller");
-    DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
-
-    switch(index)
-    {
-      case Toolkit::DevelTextField::Property::RENDERING_BACKEND:
-      {
-        value = impl.mRenderingBackend;
-        break;
-      }
-      case Toolkit::TextField::Property::TEXT:
-      {
-        std::string text;
-        impl.mController->GetText(text);
-        DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p returning text: %s\n", impl.mController.Get(), text.c_str());
-        value = text;
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
-      {
-        std::string text;
-        impl.mController->GetPlaceholderText(Controller::PLACEHOLDER_TYPE_INACTIVE, text);
-        value = text;
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
-      {
-        std::string text;
-        impl.mController->GetPlaceholderText(Controller::PLACEHOLDER_TYPE_ACTIVE, text);
-        value = text;
-        break;
-      }
-      case Toolkit::TextField::Property::FONT_FAMILY:
-      {
-        value = impl.mController->GetDefaultFontFamily();
-        break;
-      }
-      case Toolkit::TextField::Property::FONT_STYLE:
-      {
-        GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::POINT_SIZE:
-      {
-        value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE);
-        break;
-      }
-      case Toolkit::TextField::Property::MAX_LENGTH:
-      {
-        value = impl.mController->GetMaximumNumberOfCharacters();
-        break;
-      }
-      case Toolkit::TextField::Property::EXCEED_POLICY:
-      {
-        value = impl.mExceedPolicy;
-        break;
-      }
-      case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
-      {
-        const char* name = Text::GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment());
-
-        if(name)
-        {
-          value = std::string(name);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
-      {
-        const char* name = Text::GetVerticalAlignmentString(impl.mController->GetVerticalAlignment());
-
-        if(name)
-        {
-          value = std::string(name);
-        }
-        break;
-      }
-      case Toolkit::TextField::Property::TEXT_COLOR:
-      {
-        value = impl.mController->GetDefaultColor();
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
-      {
-        value = impl.mController->GetPlaceholderTextColor();
-        break;
-      }
-      case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
-      {
-        value = impl.mDecorator->GetColor(PRIMARY_CURSOR);
-        break;
-      }
-      case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
-      {
-        value = impl.mDecorator->GetColor(SECONDARY_CURSOR);
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
-      {
-        value = impl.mController->GetEnableCursorBlink();
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
-      {
-        value = impl.mDecorator->GetCursorBlinkInterval();
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
-      {
-        value = impl.mDecorator->GetCursorBlinkDuration();
-        break;
-      }
-      case Toolkit::TextField::Property::CURSOR_WIDTH:
-      {
-        value = impl.mDecorator->GetCursorWidth();
-        break;
-      }
-      case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
-      {
-        value = impl.mDecorator->GetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
-      {
-        value = impl.mDecorator->GetHandleImage(GRAB_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextField::Property::SCROLL_THRESHOLD:
-      {
-        value = impl.mDecorator->GetScrollThreshold();
-        break;
-      }
-      case Toolkit::TextField::Property::SCROLL_SPEED:
-      {
-        value = impl.mDecorator->GetScrollSpeed();
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
-      {
-        impl.GetHandleImagePropertyValue(value, LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
-      {
-        impl.GetHandleImagePropertyValue(value, RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED);
-        break;
-      }
-      case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
-      {
-        value = impl.mDecorator->GetHighlightColor();
-        break;
-      }
-      case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
-      {
-        Rect<int> boundingBox;
-        impl.mDecorator->GetBoundingBox(boundingBox);
-        value = boundingBox;
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
-      {
-        Property::Map map;
-        impl.mInputMethodOptions.RetrieveProperty(map);
-        value = map;
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_COLOR:
-      {
-        value = impl.mController->GetInputColor();
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_MARKUP:
-      {
-        value = impl.mController->IsMarkupProcessorEnabled();
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
-      {
-        value = impl.mController->GetInputFontFamily();
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_FONT_STYLE:
-      {
-        GetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_POINT_SIZE:
-      {
-        value = impl.mController->GetInputFontPointSize();
-        break;
-      }
-      case Toolkit::TextField::Property::UNDERLINE:
-      {
-        GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_UNDERLINE:
-      {
-        GetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::SHADOW:
-      {
-        GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_SHADOW:
-      {
-        GetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::EMBOSS:
-      {
-        GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_EMBOSS:
-      {
-        GetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::OUTLINE:
-      {
-        GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
-        break;
-      }
-      case Toolkit::TextField::Property::INPUT_OUTLINE:
-      {
-        GetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
-        break;
-      }
-      case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
-      {
-        Property::Map map;
-        impl.mController->GetHiddenInputOption(map);
-        value = map;
-        break;
-      }
-      case Toolkit::TextField::Property::PIXEL_SIZE:
-      {
-        value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE);
-        break;
-      }
-      case Toolkit::TextField::Property::ENABLE_SELECTION:
-      {
-        value = impl.mController->IsSelectionEnabled();
-        break;
-      }
-      case Toolkit::TextField::Property::PLACEHOLDER:
-      {
-        Property::Map map;
-        impl.mController->GetPlaceholderProperty(map);
-        value = map;
-        break;
-      }
-      case Toolkit::TextField::Property::ELLIPSIS:
-      {
-        value = impl.mController->IsTextElideEnabled();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
-      {
-        value = impl.mController->IsShiftSelectionEnabled();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
-      {
-        value = impl.mController->IsGrabHandleEnabled();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
-      {
-        value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
-      {
-        value = impl.mController->IsGrabHandlePopupEnabled();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::BACKGROUND:
-      {
-        value = impl.mController->GetBackgroundColor();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::SELECTED_TEXT:
-      {
-        value = impl.mController->GetSelectedText();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::SELECTED_TEXT_START:
-      {
-        Uint32Pair range = impl.GetTextSelectionRange();
-        value            = static_cast<int>(range.first);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::SELECTED_TEXT_END:
-      {
-        Uint32Pair range = impl.GetTextSelectionRange();
-        value            = static_cast<int>(range.second);
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ENABLE_EDITING:
-      {
-        value = impl.IsEditable();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::FONT_SIZE_SCALE:
-      {
-        value = impl.mController->GetFontSizeScale();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::PRIMARY_CURSOR_POSITION:
-      {
-        value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
-        break;
-      }
-      case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
-      {
-        value = impl.mDecorator->GetHandleColor();
-        break;
-      }
-      case Toolkit::DevelTextField::Property::INPUT_FILTER:
-      {
-        Property::Map map;
-        impl.mController->GetInputFilterOption(map);
-        value = map;
-        break;
-      }
-      case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
-      {
-        value = impl.mController->GetEllipsisPosition();
-        break;
-      }
-    } //switch
+    value = PropertyHandler::GetProperty(textField, index);
   }
 
   return value;
@@ -1441,13 +523,13 @@ void TextField::OnInitialize()
 
 void TextField::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnStyleChange\n");
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnStyleChange\n");
 
   switch(change)
   {
     case StyleChange::DEFAULT_FONT_CHANGE:
     {
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnStyleChange DEFAULT_FONT_CHANGE\n");
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnStyleChange DEFAULT_FONT_CHANGE\n");
       const std::string& newFont = GetImpl(styleManager).GetDefaultFontFamily();
       // Property system did not set the font so should update it.
       mController->UpdateAfterFontChange(newFont);
@@ -1501,7 +583,7 @@ void TextField::ResizeActor(Actor& actor, const Vector2& size)
 
 void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField OnRelayout\n");
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField OnRelayout\n");
 
   Actor self = Self();
 
@@ -1540,7 +622,7 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
      !mRenderer)
   {
-    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnRelayout %p Displaying new contents\n", mController.Get());
+    DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnRelayout %p Displaying new contents\n", mController.Get());
 
     if(mDecorator &&
        (Text::Controller::NONE_UPDATED != (Text::Controller::DECORATOR_UPDATED & updateTextType)))
@@ -1598,106 +680,12 @@ Text::ControllerPtr TextField::GetTextController()
 
 void TextField::RenderText(Text::Controller::UpdateTextType updateTextType)
 {
-  Actor renderableActor;
-
-  if(Text::Controller::NONE_UPDATED != (Text::Controller::MODEL_UPDATED & updateTextType))
-  {
-    if(mRenderer)
-    {
-      Dali::Toolkit::TextField handle = Dali::Toolkit::TextField(GetOwner());
-
-      renderableActor = mRenderer->Render(mController->GetView(),
-                                          handle,
-                                          Property::INVALID_INDEX, // Animatable property not supported
-                                          mAlignmentOffset,
-                                          DepthIndex::CONTENT);
-    }
-
-    if(renderableActor != mRenderableActor)
-    {
-      UnparentAndReset(mBackgroundActor);
-      UnparentAndReset(mRenderableActor);
-      mRenderableActor = renderableActor;
-
-      if(mRenderableActor)
-      {
-        mBackgroundActor = mController->CreateBackgroundActor();
-      }
-    }
-  }
-
-  if(mRenderableActor)
-  {
-    const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
-
-    float renderableActorPositionX, renderableActorPositionY;
-
-    if(mStencil)
-    {
-      renderableActorPositionX = scrollOffset.x + mAlignmentOffset;
-      renderableActorPositionY = scrollOffset.y;
-    }
-    else
-    {
-      Extents padding;
-      padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
-
-      // Support Right-To-Left of padding
-      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
-      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
-      {
-        std::swap(padding.start, padding.end);
-      }
-
-      renderableActorPositionX = scrollOffset.x + mAlignmentOffset + padding.start;
-      renderableActorPositionY = scrollOffset.y + padding.top;
-    }
-
-    mRenderableActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY));
-
-    // Make sure the actors are parented correctly with/without clipping
-    Actor self = mStencil ? mStencil : Self();
-
-    Actor highlightActor;
-
-    for(std::vector<Actor>::iterator it    = mClippingDecorationActors.begin(),
-                                     endIt = mClippingDecorationActors.end();
-        it != endIt;
-        ++it)
-    {
-      self.Add(*it);
-      it->LowerToBottom();
-
-      if(it->GetProperty<std::string>(Dali::Actor::Property::NAME) == "HighlightActor")
-      {
-        highlightActor = *it;
-      }
-    }
-    mClippingDecorationActors.clear();
-
-    self.Add(mRenderableActor);
-
-    if(mBackgroundActor)
-    {
-      if(mDecorator && mDecorator->IsHighlightVisible())
-      {
-        self.Add(mBackgroundActor);
-        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY)); // In text field's coords.
-        mBackgroundActor.LowerBelow(highlightActor);
-      }
-      else
-      {
-        mRenderableActor.Add(mBackgroundActor);
-        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); // In renderable actor's coords.
-        mBackgroundActor.LowerToBottom();
-      }
-    }
-  }
+  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, updateTextType);
 }
 
 void TextField::OnKeyInputFocusGained()
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get());
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get());
   if(mInputMethodContext && IsEditable())
   {
     // All input panel properties, such as layout, return key type, and input hint, should be set before input panel activates (or shows).
@@ -1728,7 +716,7 @@ void TextField::OnKeyInputFocusGained()
 
 void TextField::OnKeyInputFocusLost()
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get());
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get());
   if(mInputMethodContext)
   {
     mInputMethodContext.StatusChangedSignal().Disconnect(this, &TextField::KeyboardStatusChanged);
@@ -1760,7 +748,7 @@ bool TextField::OnAccessibilityActivated()
 
 void TextField::OnTap(const TapGesture& gesture)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get());
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get());
   if(mInputMethodContext && IsEditable())
   {
     mInputMethodContext.Activate();
@@ -1796,7 +784,7 @@ void TextField::OnLongPress(const LongPressGesture& gesture)
 
 bool TextField::OnKeyEvent(const KeyEvent& event)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.GetKeyCode());
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.GetKeyCode());
 
   if(Dali::DALI_KEY_ESCAPE == event.GetKeyCode() && mController->ShouldClearFocusOnEscape())
   {
@@ -1894,51 +882,7 @@ void TextField::MaxLengthReached()
 void TextField::InputStyleChanged(Text::InputStyle::Mask inputStyleMask)
 {
   Dali::Toolkit::TextField handle(GetOwner());
-
-  Toolkit::TextField::InputStyle::Mask fieldInputStyleMask = Toolkit::TextField::InputStyle::NONE;
-
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_COLOR))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::COLOR);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_FAMILY))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_FAMILY);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_POINT_SIZE))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::POINT_SIZE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WEIGHT))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_WIDTH))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_FONT_SLANT))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_UNDERLINE))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::UNDERLINE);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_SHADOW))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::SHADOW);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_EMBOSS))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::EMBOSS);
-  }
-  if(InputStyle::NONE != static_cast<InputStyle::Mask>(inputStyleMask & InputStyle::INPUT_OUTLINE))
-  {
-    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>(fieldInputStyleMask | Toolkit::TextField::InputStyle::OUTLINE);
-  }
-
-  mInputStyleChangedSignal.Emit(handle, fieldInputStyleMask);
+  mInputStyleChangedSignal.Emit(handle, ConvertInputStyle(inputStyleMask));
 }
 
 void TextField::AnchorClicked(const std::string& href)
@@ -2041,7 +985,7 @@ void TextField::OnSceneConnect(Dali::Actor actor)
 
 InputMethodContext::CallbackData TextField::OnInputMethodContextEvent(Dali::InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName);
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName);
   return mController->OnInputMethodContextEvent(inputMethodContext, inputMethodContextEvent);
 }
 
@@ -2050,8 +994,9 @@ void TextField::GetHandleImagePropertyValue(Property::Value& value, Text::Handle
   if(mDecorator)
   {
     Property::Map map;
-    map[IMAGE_MAP_FILENAME_STRING] = mDecorator->GetHandleImage(handleType, handleImageType);
-    value                          = map;
+    map[PropertyHandler::IMAGE_MAP_FILENAME_STRING] = mDecorator->GetHandleImage(handleType, handleImageType);
+
+    value = map;
   }
 }
 
@@ -2083,7 +1028,7 @@ void TextField::OnClipboardTextSelected(ClipboardEventNotifier& clipboard)
 
 void TextField::KeyboardStatusChanged(bool keyboardShown)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextField::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown);
+  DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown);
 
   // Just hide the grab handle when keyboard is hidden.
   if(!keyboardShown)
index 0472aa8..b65e953 100644 (file)
@@ -470,6 +470,8 @@ private: // Data
   uint32_t mOldSelectionEnd;
 
 protected:
+  struct PropertyHandler;
+
   /**
    * @brief This structure is to connect TextField with Accessible functions.
    */
diff --git a/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp b/dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp
new file mode 100644 (file)
index 0000000..04a5082
--- /dev/null
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-field-property-handler.h>
+
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/devel-api/text/rendering-backend.h>
+
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali/integration-api/debug.h>
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gTextFieldLogFilter;
+#endif
+
+namespace Dali::Toolkit::Internal
+{
+const char* const TextField::PropertyHandler::IMAGE_MAP_FILENAME_STRING{"filename"};
+
+/// Retrieves a filename from a value that is a Property::Map
+std::string TextField::PropertyHandler::GetImageFileNameFromPropertyValue(const Property::Value& value)
+{
+  std::string          filename;
+  const Property::Map* map = value.GetMap();
+  if(map)
+  {
+    const Property::Value* filenameValue = map->Find(TextField::PropertyHandler::IMAGE_MAP_FILENAME_STRING);
+    if(filenameValue)
+    {
+      filenameValue->Get(filename);
+    }
+  }
+  return filename;
+}
+
+void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Property::Index index, const Property::Value& value)
+{
+  TextField& impl(GetImpl(textField));
+  DALI_ASSERT_DEBUG(impl.mController && "No text controller");
+  DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
+
+  switch(index)
+  {
+    case Toolkit::DevelTextField::Property::RENDERING_BACKEND:
+    {
+      int backend = value.Get<int>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend);
+
+#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
+      if(DevelText::RENDERING_VECTOR_BASED == backend)
+      {
+        backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
+      }
+#endif
+      if(impl.mRenderingBackend != backend)
+      {
+        impl.mRenderingBackend = backend;
+        impl.mRenderer.Reset();
+
+        // When using the vector-based rendering, the size of the GLyphs are different
+        TextAbstraction::GlyphType glyphType = (DevelText::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+        impl.mController->SetGlyphType(glyphType);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::TEXT:
+    {
+      const std::string& text = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p TEXT %s\n", impl.mController.Get(), text.c_str());
+
+      impl.mController->SetText(text);
+      break;
+    }
+
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
+    {
+      const std::string& text = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str());
+
+      impl.mController->SetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_INACTIVE, text);
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
+    {
+      const std::string& text = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_FOCUSED %s\n", impl.mController.Get(), text.c_str());
+
+      impl.mController->SetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_ACTIVE, text);
+      break;
+    }
+    case Toolkit::TextField::Property::FONT_FAMILY:
+    {
+      const std::string& fontFamily = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
+      impl.mController->SetDefaultFontFamily(fontFamily);
+      break;
+    }
+    case Toolkit::TextField::Property::FONT_STYLE:
+    {
+      SetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::POINT_SIZE:
+    {
+      const float pointSize = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p POINT_SIZE %f\n", impl.mController.Get(), pointSize);
+
+      if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE), pointSize))
+      {
+        impl.mController->SetDefaultFontSize(pointSize, Text::Controller::POINT_SIZE);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::MAX_LENGTH:
+    {
+      const int max = value.Get<int>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p MAX_LENGTH %d\n", impl.mController.Get(), max);
+
+      impl.mController->SetMaximumNumberOfCharacters(max);
+      break;
+    }
+    case Toolkit::TextField::Property::EXCEED_POLICY:
+    {
+      impl.mExceedPolicy = value.Get<int>();
+
+      if(Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == impl.mExceedPolicy)
+      {
+        impl.EnableClipping();
+      }
+      else
+      {
+        UnparentAndReset(impl.mStencil);
+      }
+      impl.RequestTextRelayout();
+      break;
+    }
+
+    case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
+    {
+      Text::HorizontalAlignment::Type alignment(static_cast<Text::HorizontalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Text::GetHorizontalAlignmentEnumeration(value, alignment))
+      {
+        DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
+        impl.mController->SetHorizontalAlignment(alignment);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
+    {
+      Toolkit::Text::VerticalAlignment::Type alignment(static_cast<Text::VerticalAlignment::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Text::GetVerticalAlignmentEnumeration(value, alignment))
+      {
+        impl.mController->SetVerticalAlignment(alignment);
+        DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %d\n", impl.mController.Get(), alignment);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::TEXT_COLOR:
+    {
+      const Vector4& textColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
+
+      if(impl.mController->GetDefaultColor() != textColor)
+      {
+        impl.mController->SetDefaultColor(textColor);
+        impl.mController->SetInputColor(textColor);
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
+    {
+      const Vector4& textColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a);
+
+      if(impl.mController->GetPlaceholderTextColor() != textColor)
+      {
+        impl.mController->SetPlaceholderTextColor(textColor);
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
+    {
+      const Vector4& color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetCursorColor(Toolkit::Text::PRIMARY_CURSOR, color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
+    {
+      const Vector4& color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetCursorColor(Toolkit::Text::SECONDARY_CURSOR, color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
+    {
+      const bool enable = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable);
+
+      impl.mController->SetEnableCursorBlink(enable);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
+    {
+      const float interval = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval);
+
+      impl.mDecorator->SetCursorBlinkInterval(interval);
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
+    {
+      const float duration = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration);
+
+      impl.mDecorator->SetCursorBlinkDuration(duration);
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_WIDTH:
+    {
+      const int width = value.Get<int>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p CURSOR_WIDTH %d\n", impl.mController.Get(), width);
+
+      impl.mDecorator->SetCursorWidth(width);
+      impl.mController->GetLayoutEngine().SetCursorWidth(width);
+      break;
+    }
+    case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
+    {
+      const std::string imageFileName = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
+
+      if(imageFileName.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::GRAB_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, imageFileName);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
+    {
+      const std::string imageFileName = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), imageFileName.c_str());
+
+      if(imageFileName.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::GRAB_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, imageFileName);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SCROLL_THRESHOLD:
+    {
+      const float threshold = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold);
+
+      impl.mDecorator->SetScrollThreshold(threshold);
+      break;
+    }
+    case Toolkit::TextField::Property::SCROLL_SPEED:
+    {
+      const float speed = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::Verbose, "TextField %p SCROLL_SPEED %f\n", impl.mController.Get(), speed);
+
+      impl.mDecorator->SetScrollSpeed(speed);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_RELEASED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE, Toolkit::Text::HANDLE_IMAGE_PRESSED, filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::LEFT_SELECTION_HANDLE_MARKER,
+                                        Toolkit::Text::HANDLE_IMAGE_RELEASED,
+                                        filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+    {
+      const std::string filename = GetImageFileNameFromPropertyValue(value);
+
+      if(filename.size())
+      {
+        impl.mDecorator->SetHandleImage(Toolkit::Text::RIGHT_SELECTION_HANDLE_MARKER,
+                                        Toolkit::Text::HANDLE_IMAGE_RELEASED,
+                                        filename);
+        impl.RequestTextRelayout();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
+    {
+      const Vector4 color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetHighlightColor(color);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
+    {
+      const Rect<int>& box = value.Get<Rect<int> >();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height);
+
+      impl.mDecorator->SetBoundingBox(box);
+      impl.RequestTextRelayout();
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mInputMethodOptions.ApplyProperty(*map);
+      }
+      impl.mController->SetInputModePassword(impl.mInputMethodOptions.IsPassword());
+
+      Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+      if(control == textField)
+      {
+        impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_COLOR:
+    {
+      const Vector4& inputColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a);
+
+      impl.mController->SetInputColor(inputColor);
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_MARKUP:
+    {
+      const bool enableMarkup = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup);
+
+      impl.mController->SetMarkupProcessorEnabled(enableMarkup);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
+    {
+      const std::string& fontFamily = value.Get<std::string>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str());
+      impl.mController->SetInputFontFamily(fontFamily);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_FONT_STYLE:
+    {
+      SetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_POINT_SIZE:
+    {
+      const float pointSize = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize);
+      impl.mController->SetInputFontPointSize(pointSize);
+      break;
+    }
+    case Toolkit::TextField::Property::UNDERLINE:
+    {
+      const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_UNDERLINE:
+    {
+      const bool update = SetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::SHADOW:
+    {
+      const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_SHADOW:
+    {
+      const bool update = SetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::EMBOSS:
+    {
+      const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_EMBOSS:
+    {
+      const bool update = SetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::OUTLINE:
+    {
+      const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_OUTLINE:
+    {
+      const bool update = SetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      if(update)
+      {
+        impl.mRenderer.Reset();
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mController->SetHiddenInputOption(*map);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::PIXEL_SIZE:
+    {
+      const float pixelSize = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize);
+
+      if(!Equals(impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE), pixelSize))
+      {
+        impl.mController->SetDefaultFontSize(pixelSize, Text::Controller::PIXEL_SIZE);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_SELECTION:
+    {
+      const bool enableSelection = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection);
+      impl.mController->SetSelectionEnabled(enableSelection);
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mController->SetPlaceholderProperty(*map);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::ELLIPSIS:
+    {
+      const bool ellipsis = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
+
+      impl.mController->SetTextElideEnabled(ellipsis);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
+    {
+      const bool shiftSelection = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection);
+
+      impl.mController->SetShiftSelectionEnabled(shiftSelection);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
+    {
+      const bool grabHandleEnabled = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled);
+
+      impl.mController->SetGrabHandleEnabled(grabHandleEnabled);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+    {
+      impl.mController->SetMatchLayoutDirection(value.Get<bool>() ? DevelText::MatchLayoutDirection::LOCALE : DevelText::MatchLayoutDirection::CONTENTS);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
+    {
+      const bool grabHandlePopupEnabled = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
+
+      impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::BACKGROUND:
+    {
+      const Vector4 backgroundColor = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p BACKGROUND %f,%f,%f,%f\n", impl.mController.Get(), backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a);
+
+      impl.mController->SetBackgroundEnabled(true);
+      impl.mController->SetBackgroundColor(backgroundColor);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::SELECTED_TEXT_START:
+    {
+      uint32_t start = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p SELECTED_TEXT_START %d\n", impl.mController.Get(), start);
+      impl.SetTextSelectionRange(&start, nullptr);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::SELECTED_TEXT_END:
+    {
+      uint32_t end = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p SELECTED_TEXT_END %d\n", impl.mController.Get(), end);
+      impl.SetTextSelectionRange(nullptr, &end);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_EDITING:
+    {
+      const bool editable = value.Get<bool>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p ENABLE_EDITING %d\n", impl.mController.Get(), editable);
+      impl.SetEditable(editable);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::FONT_SIZE_SCALE:
+    {
+      const float scale = value.Get<float>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p FONT_SIZE_SCALE %f\n", impl.mController.Get(), scale);
+
+      if(!Equals(impl.mController->GetFontSizeScale(), scale))
+      {
+        impl.mController->SetFontSizeScale(scale);
+      }
+      break;
+    }
+    case Toolkit::DevelTextField::Property::PRIMARY_CURSOR_POSITION:
+    {
+      uint32_t position = static_cast<uint32_t>(value.Get<int>());
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_POSITION %d\n", impl.mController.Get(), position);
+      if(impl.mController->SetPrimaryCursorPosition(position, impl.HasKeyInputFocus()))
+      {
+        impl.SetKeyInputFocus();
+      }
+      break;
+    }
+    case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
+    {
+      const Vector4 color = value.Get<Vector4>();
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p GRAB_HANDLE_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a);
+
+      impl.mDecorator->SetHandleColor(color);
+      impl.RequestTextRelayout();
+      break;
+    }
+
+    case Toolkit::DevelTextField::Property::INPUT_FILTER:
+    {
+      const Property::Map* map = value.GetMap();
+      if(map)
+      {
+        impl.mController->SetInputFilterOption(*map);
+      }
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+    {
+      DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+      if(Text::GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+      {
+        DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+        impl.mController->SetEllipsisPosition(ellipsisPositionType);
+      }
+      break;
+    }
+  }
+}
+
+Property::Value TextField::PropertyHandler::GetProperty(Toolkit::TextField textField, Property::Index index)
+{
+  Property::Value value;
+  TextField&      impl(GetImpl(textField));
+  DALI_ASSERT_DEBUG(impl.mController && "No text controller");
+  DALI_ASSERT_DEBUG(impl.mDecorator && "No text decorator");
+
+  switch(index)
+  {
+    case Toolkit::DevelTextField::Property::RENDERING_BACKEND:
+    {
+      value = impl.mRenderingBackend;
+      break;
+    }
+    case Toolkit::TextField::Property::TEXT:
+    {
+      std::string text;
+      impl.mController->GetText(text);
+      DALI_LOG_INFO(gTextFieldLogFilter, Debug::General, "TextField %p returning text: %s\n", impl.mController.Get(), text.c_str());
+      value = text;
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
+    {
+      std::string text;
+      impl.mController->GetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_INACTIVE, text);
+      value = text;
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
+    {
+      std::string text;
+      impl.mController->GetPlaceholderText(Text::Controller::PLACEHOLDER_TYPE_ACTIVE, text);
+      value = text;
+      break;
+    }
+    case Toolkit::TextField::Property::FONT_FAMILY:
+    {
+      value = impl.mController->GetDefaultFontFamily();
+      break;
+    }
+    case Toolkit::TextField::Property::FONT_STYLE:
+    {
+      GetFontStyleProperty(impl.mController, value, Text::FontStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::POINT_SIZE:
+    {
+      value = impl.mController->GetDefaultFontSize(Text::Controller::POINT_SIZE);
+      break;
+    }
+    case Toolkit::TextField::Property::MAX_LENGTH:
+    {
+      value = impl.mController->GetMaximumNumberOfCharacters();
+      break;
+    }
+    case Toolkit::TextField::Property::EXCEED_POLICY:
+    {
+      value = impl.mExceedPolicy;
+      break;
+    }
+    case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
+    {
+      const char* name = Text::GetHorizontalAlignmentString(impl.mController->GetHorizontalAlignment());
+      if(name)
+      {
+        value = std::string(name);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
+    {
+      const char* name = Text::GetVerticalAlignmentString(impl.mController->GetVerticalAlignment());
+
+      if(name)
+      {
+        value = std::string(name);
+      }
+      break;
+    }
+    case Toolkit::TextField::Property::TEXT_COLOR:
+    {
+      value = impl.mController->GetDefaultColor();
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
+    {
+      value = impl.mController->GetPlaceholderTextColor();
+      break;
+    }
+    case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
+    {
+      value = impl.mDecorator->GetColor(Text::PRIMARY_CURSOR);
+      break;
+    }
+    case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
+    {
+      value = impl.mDecorator->GetColor(Text::SECONDARY_CURSOR);
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
+    {
+      value = impl.mController->GetEnableCursorBlink();
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
+    {
+      value = impl.mDecorator->GetCursorBlinkInterval();
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
+    {
+      value = impl.mDecorator->GetCursorBlinkDuration();
+      break;
+    }
+    case Toolkit::TextField::Property::CURSOR_WIDTH:
+    {
+      value = impl.mDecorator->GetCursorWidth();
+      break;
+    }
+    case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
+    {
+      value = impl.mDecorator->GetHandleImage(Text::GRAB_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
+    {
+      value = impl.mDecorator->GetHandleImage(Text::GRAB_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextField::Property::SCROLL_THRESHOLD:
+    {
+      value = impl.mDecorator->GetScrollThreshold();
+      break;
+    }
+    case Toolkit::TextField::Property::SCROLL_SPEED:
+    {
+      value = impl.mDecorator->GetScrollSpeed();
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE, Text::HANDLE_IMAGE_PRESSED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::LEFT_SELECTION_HANDLE_MARKER, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+    {
+      impl.GetHandleImagePropertyValue(value, Text::RIGHT_SELECTION_HANDLE_MARKER, Text::HANDLE_IMAGE_RELEASED);
+      break;
+    }
+    case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
+    {
+      value = impl.mDecorator->GetHighlightColor();
+      break;
+    }
+    case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
+    {
+      Rect<int> boundingBox;
+      impl.mDecorator->GetBoundingBox(boundingBox);
+      value = boundingBox;
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
+    {
+      Property::Map map;
+      impl.mInputMethodOptions.RetrieveProperty(map);
+      value = map;
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_COLOR:
+    {
+      value = impl.mController->GetInputColor();
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_MARKUP:
+    {
+      value = impl.mController->IsMarkupProcessorEnabled();
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
+    {
+      value = impl.mController->GetInputFontFamily();
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_FONT_STYLE:
+    {
+      GetFontStyleProperty(impl.mController, value, Text::FontStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_POINT_SIZE:
+    {
+      value = impl.mController->GetInputFontPointSize();
+      break;
+    }
+    case Toolkit::TextField::Property::UNDERLINE:
+    {
+      GetUnderlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_UNDERLINE:
+    {
+      GetUnderlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::SHADOW:
+    {
+      GetShadowProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_SHADOW:
+    {
+      GetShadowProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::EMBOSS:
+    {
+      GetEmbossProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_EMBOSS:
+    {
+      GetEmbossProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::OUTLINE:
+    {
+      GetOutlineProperties(impl.mController, value, Text::EffectStyle::DEFAULT);
+      break;
+    }
+    case Toolkit::TextField::Property::INPUT_OUTLINE:
+    {
+      GetOutlineProperties(impl.mController, value, Text::EffectStyle::INPUT);
+      break;
+    }
+    case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
+    {
+      Property::Map map;
+      impl.mController->GetHiddenInputOption(map);
+      value = map;
+      break;
+    }
+    case Toolkit::TextField::Property::PIXEL_SIZE:
+    {
+      value = impl.mController->GetDefaultFontSize(Text::Controller::PIXEL_SIZE);
+      break;
+    }
+    case Toolkit::TextField::Property::ENABLE_SELECTION:
+    {
+      value = impl.mController->IsSelectionEnabled();
+      break;
+    }
+    case Toolkit::TextField::Property::PLACEHOLDER:
+    {
+      Property::Map map;
+      impl.mController->GetPlaceholderProperty(map);
+      value = map;
+      break;
+    }
+    case Toolkit::TextField::Property::ELLIPSIS:
+    {
+      value = impl.mController->IsTextElideEnabled();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
+    {
+      value = impl.mController->IsShiftSelectionEnabled();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
+    {
+      value = impl.mController->IsGrabHandleEnabled();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+    {
+      value = impl.mController->GetMatchLayoutDirection() != DevelText::MatchLayoutDirection::CONTENTS;
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
+    {
+      value = impl.mController->IsGrabHandlePopupEnabled();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::BACKGROUND:
+    {
+      value = impl.mController->GetBackgroundColor();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::SELECTED_TEXT:
+    {
+      value = impl.mController->GetSelectedText();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::SELECTED_TEXT_START:
+    {
+      Uint32Pair range = impl.GetTextSelectionRange();
+      value            = static_cast<int>(range.first);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::SELECTED_TEXT_END:
+    {
+      Uint32Pair range = impl.GetTextSelectionRange();
+      value            = static_cast<int>(range.second);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ENABLE_EDITING:
+    {
+      value = impl.IsEditable();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::FONT_SIZE_SCALE:
+    {
+      value = impl.mController->GetFontSizeScale();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::PRIMARY_CURSOR_POSITION:
+    {
+      value = static_cast<int>(impl.mController->GetPrimaryCursorPosition());
+      break;
+    }
+    case Toolkit::DevelTextField::Property::GRAB_HANDLE_COLOR:
+    {
+      value = impl.mDecorator->GetHandleColor();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::INPUT_FILTER:
+    {
+      Property::Map map;
+      impl.mController->GetInputFilterOption(map);
+      value = map;
+      break;
+    }
+    case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+    {
+      value = impl.mController->GetEllipsisPosition();
+      break;
+    }
+  } //switch
+  return value;
+}
+
+} // namespace Dali::Toolkit::Internal
diff --git a/dali-toolkit/internal/controls/text-controls/text-field-property-handler.h b/dali-toolkit/internal/controls/text-controls/text-field-property-handler.h
new file mode 100644 (file)
index 0000000..f7b5c53
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_FIELD_PROPERTY_HANDLER_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_FIELD_PROPERTY_HANDLER_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+
+namespace Dali::Toolkit::Internal
+{
+/**
+ * Class to manage properties for the TextField
+ */
+struct TextField::PropertyHandler
+{
+  static const char* const IMAGE_MAP_FILENAME_STRING; //<<< "filename" key for image map
+
+  /**
+   * Set properties on the text field / controller / decorator
+   *
+   * @param[in] textField The handle for the text field
+   * @param[in] index The property index of the property to set
+   * @param[in] value The value to set
+   */
+  static void SetProperty(Toolkit::TextField textField, Property::Index index, const Property::Value& value);
+
+  /**
+   * Get properties from the text field / controller / decorator
+   *
+   * @param[in] textField The handle for the text field
+   * @param[in] index The property index of the property to set
+   * @return the value
+   */
+  static Property::Value GetProperty(Toolkit::TextField textField, Property::Index index);
+
+private:
+  /**
+   * Method to extract "filename" value from a Property::Map
+   *
+   * @param[in] The property value containing the Property::Map
+   * @return The resulting "filename" value if present
+   */
+  static std::string GetImageFileNameFromPropertyValue(const Property::Value& value);
+};
+
+} // namespace Dali::Toolkit::Internal
+
+#endif //DALI_TOOLKIT_INTERNAL_TEXT_FIELD_PROPERTY_HANDLER_H
index f1aa866..3229006 100644 (file)
@@ -92,6 +92,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/scene3d-view-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/gltf-loader.cpp
@@ -99,8 +100,11 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/slider/slider-impl.cpp
    ${toolkit_src_dir}/controls/super-blur-view/super-blur-view-impl.cpp
    ${toolkit_src_dir}/controls/table-view/table-view-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/common-text-utils.cpp
    ${toolkit_src_dir}/controls/text-controls/text-editor-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-editor-property-handler.cpp
    ${toolkit_src_dir}/controls/text-controls/text-field-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-field-property-handler.cpp
    ${toolkit_src_dir}/controls/text-controls/text-label-impl.cpp
    ${toolkit_src_dir}/controls/text-controls/text-selection-popup-impl.cpp
    ${toolkit_src_dir}/controls/text-controls/text-selection-toolbar-impl.cpp
@@ -155,6 +159,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/text-controller-event-handler.cpp
    ${toolkit_src_dir}/text/text-controller-impl.cpp
    ${toolkit_src_dir}/text/text-controller-impl-event-handler.cpp
+   ${toolkit_src_dir}/text/text-controller-impl-model-updater.cpp
    ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp
    ${toolkit_src_dir}/text/text-controller-placeholder-handler.cpp
    ${toolkit_src_dir}/text/text-controller-relayouter.cpp
index 13be4df..3e3d19d 100644 (file)
@@ -241,18 +241,18 @@ mediump float calculateBlurOpacity()
 
     // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
 #if IS_REQUIRED_ROUNDED_CORNER
-    // NOTE : lowspec HW cannot calculate here. need to reduce numeric error
-    mediump float A = (cr * cr - 2.0 * cy * cy);
-    mediump float B = cy * (v.x + v.y);
-    mediump float V = dot(v,v);
-    mediump float D = B * B + A * V;
+    // Note : lowspec HW cannot calculate here. need to reduce numeric error
+    highp float A = (cr * cr - 2.0 * cy * cy);
+    highp float B = cy * (v.x + v.y);
+    highp float V = dot(v,v);
+    highp float D = B * B + A * V;
     potential = V * (cr + cy) / (sqrt(D) + B);
 #else
     // We can simplify this value cause cy = 0.8 * blurRadius, cr = 1.2 * blurRadius
     // potential = 5.0*(sqrt(4.0*(v.x+v.y)^2 + dot(v,v)) - 2.0*(v.x+v.y));
     //           = 10.0*(v.x+v.y) * (sqrt(1.0 + (length(v) / (2.0*(v.x+v.y)))^2) - 1.0);
     //           = 10.0*(v.x+v.y) * (sqrt(1.25 - x + x^2) - 1.0);
-    //          ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^4)) (Taylor series)
+    //          ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^5)) (Taylor series)
     //          ~= -1.0557281 * (v.x + v.y) + 2.236068 * length(v) - ~~~ (here, x <= 0.5 * (1.0 - sqrt(0.5)) < 0.1464467)
     // Note : This simplify need cause we should use it on lowspec HW.
     mediump float x = 0.5 * (1.0 - length(v) / (v.x + v.y));
index a0e6ae5..82470f8 100644 (file)
@@ -228,7 +228,8 @@ void MultilanguageSupport::SetScripts(const Vector<Character>& text,
       // Check if whether is right to left markup and Keeps true if the previous value was true.
       currentScriptRun.isRightToLeft = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftMark(character);
 
-      if(TextAbstraction::EMOJI == currentScriptRun.script)
+      // ZWJ, ZWNJ between emojis should be treated as EMOJI.
+      if(TextAbstraction::EMOJI == currentScriptRun.script && !(TextAbstraction::IsZeroWidthJoiner(character) || TextAbstraction::IsZeroWidthNonJoiner(character)))
       {
         // Emojis doesn't mix well with characters common to all scripts. Insert the emoji run.
         scripts.Insert(scripts.Begin() + scriptIndex, currentScriptRun);
@@ -444,7 +445,8 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
   Vector<ScriptRun>::ConstIterator scriptRunEndIt          = scripts.End();
   bool                             isNewParagraphCharacter = false;
 
-  bool isPreviousEmojiScript = false;
+  bool   isPreviousEmojiScript = false;
+  FontId previousEmojiFontId   = 0u;
 
   CharacterIndex lastCharacter = startIndex + numberOfCharacters;
   for(Length index = startIndex; index < lastCharacter; ++index)
@@ -535,6 +537,16 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
       currentFontRun.isBoldRequired                  = false;
     }
 
+    // ZWJ, ZWNJ between emojis should use the previous emoji font.
+    if(isEmojiScript && (TextAbstraction::IsZeroWidthJoiner(character) || TextAbstraction::IsZeroWidthNonJoiner(character)))
+    {
+      if(0u != previousEmojiFontId)
+      {
+        fontId      = previousEmojiFontId;
+        isValidFont = true;
+      }
+    }
+
     // If the given font is not valid, it means either:
     // - there is no cached font for the current script yet or,
     // - the user has set a different font than the default one for the current script or,
@@ -647,6 +659,15 @@ void MultilanguageSupport::ValidateFonts(const Vector<Character>&
       }   // !isValidFont (2)
     }     // !isValidFont (1)
 
+    // Store the font id when the first character is an emoji.
+    if(isEmojiScript && !isPreviousEmojiScript)
+    {
+      if(0u != fontId)
+      {
+        previousEmojiFontId = fontId;
+      }
+    }
+
 #ifdef DEBUG_ENABLED
     {
       Dali::TextAbstraction::FontDescription description;
index 35c0a87..2187487 100644 (file)
@@ -449,7 +449,7 @@ void ViewModel::ElideGlyphs()
               // Need to reshape the glyph as the font may be different in size.
               const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
 
-              if(!firstPenSet)
+              if(!firstPenSet || EqualsZero(glyphToRemove.advance))
               {
                 const Vector2& position = *(elidedPositionsBuffer + indexOfEllipsis);
 
diff --git a/dali-toolkit/internal/text/text-controller-impl-model-updater.cpp b/dali-toolkit/internal/text/text-controller-impl-model-updater.cpp
new file mode 100644 (file)
index 0000000..1ce7516
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+
+namespace Dali::Toolkit::Text
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+// The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
+// based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+constexpr float         BRIGHTNESS_THRESHOLD = 0.179f;
+constexpr float         CONSTANT_R           = 0.2126f;
+constexpr float         CONSTANT_G           = 0.7152f;
+constexpr float         CONSTANT_B           = 0.0722f;
+constexpr Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
+constexpr Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
+constexpr Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
+constexpr Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
+} // namespace
+
+bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask operationsRequired)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
+
+  // Calculate the operations to be done.
+  const OperationsMask operations = static_cast<OperationsMask>(impl.mOperationsPending & operationsRequired);
+
+  if(Controller::NO_OPERATION == operations)
+  {
+    // Nothing to do if no operations are pending and required.
+    return false;
+  }
+
+  Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
+  Vector<Character>  displayCharacters;
+  bool               useHiddenText = false;
+  if(impl.mHiddenInput && impl.mEventData != nullptr && !impl.mEventData->mIsShowingPlaceholderText)
+  {
+    impl.mHiddenInput->Substitute(srcCharacters, displayCharacters);
+    useHiddenText = true;
+  }
+
+  Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
+  const Length       numberOfCharacters = utf32Characters.Count();
+
+  // Index to the first character of the first paragraph to be updated.
+  CharacterIndex startIndex = 0u;
+  // Number of characters of the paragraphs to be removed.
+  Length paragraphCharacters = 0u;
+
+  impl.CalculateTextUpdateIndices(paragraphCharacters);
+
+  // Check whether the indices for updating the text is valid
+  if(numberOfCharacters > 0u &&
+     (impl.mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
+         impl.mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
+  {
+    std::string currentText;
+    Utf32ToUtf8(impl.mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
+
+    DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
+    DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
+
+    // Dump mTextUpdateInfo
+    DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
+    DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", impl.mTextUpdateInfo.mCharacterIndex);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToRemove);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", impl.mTextUpdateInfo.mNumberOfCharactersToAdd);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mPreviousNumberOfCharacters);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", impl.mTextUpdateInfo.mParagraphCharacterIndex);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", impl.mTextUpdateInfo.mRequestedNumberOfCharacters);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", impl.mTextUpdateInfo.mStartGlyphIndex);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", impl.mTextUpdateInfo.mStartLineIndex);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", impl.mTextUpdateInfo.mEstimatedNumberOfLines);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", impl.mTextUpdateInfo.mClearAll);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", impl.mTextUpdateInfo.mFullRelayoutNeeded);
+    DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", impl.mTextUpdateInfo.mIsLastCharacterNewParagraph);
+
+    return false;
+  }
+
+  startIndex = impl.mTextUpdateInfo.mParagraphCharacterIndex;
+
+  if(impl.mTextUpdateInfo.mClearAll ||
+     (0u != paragraphCharacters))
+  {
+    impl.ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
+  }
+
+  impl.mTextUpdateInfo.mClearAll = false;
+
+  // Whether the model is updated.
+  bool updated = false;
+
+  Vector<LineBreakInfo>& lineBreakInfo               = impl.mModel->mLogicalModel->mLineBreakInfo;
+  const Length           requestedNumberOfCharacters = impl.mTextUpdateInfo.mRequestedNumberOfCharacters;
+
+  if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+  {
+    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
+    // calculate the bidirectional info for each 'paragraph'.
+    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
+    // is not shaped together).
+    lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
+
+    SetLineBreakInfo(utf32Characters,
+                     startIndex,
+                     requestedNumberOfCharacters,
+                     lineBreakInfo);
+
+    if(impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+        impl.mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+    {
+      CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
+      LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+      for(CharacterIndex index = startIndex; index < end; index++)
+      {
+        CharacterIndex wordEnd = index;
+        while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+        {
+          wordEnd++;
+        }
+
+        if((wordEnd + 1) == end) // add last char
+        {
+          wordEnd++;
+        }
+
+        Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+        for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+        {
+          if(hyphens[i])
+          {
+            *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+          }
+        }
+
+        index = wordEnd;
+      }
+    }
+
+    // Create the paragraph info.
+    impl.mModel->mLogicalModel->CreateParagraphInfo(startIndex,
+                                                    requestedNumberOfCharacters);
+    updated = true;
+  }
+
+  const bool getScripts    = Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations);
+  const bool validateFonts = Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations);
+
+  Vector<ScriptRun>& scripts    = impl.mModel->mLogicalModel->mScriptRuns;
+  Vector<FontRun>&   validFonts = impl.mModel->mLogicalModel->mFontRuns;
+
+  if(getScripts || validateFonts)
+  {
+    // Validates the fonts assigned by the application or assigns default ones.
+    // It makes sure all the characters are going to be rendered by the correct font.
+    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+    if(getScripts)
+    {
+      // Retrieves the scripts used in the text.
+      multilanguageSupport.SetScripts(utf32Characters,
+                                      startIndex,
+                                      requestedNumberOfCharacters,
+                                      scripts);
+    }
+
+    if(validateFonts)
+    {
+      // Validate the fonts set through the mark-up string.
+      Vector<FontDescriptionRun>& fontDescriptionRuns = impl.mModel->mLogicalModel->mFontDescriptionRuns;
+
+      // Get the default font's description.
+      TextAbstraction::FontDescription defaultFontDescription;
+      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * impl.mFontSizeScale;
+
+      //Get the number of points per one unit of point-size
+      uint32_t numberOfPointsPerOneUnitOfPointSize = impl.mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
+
+      if(impl.IsShowingPlaceholderText() && impl.mEventData && (nullptr != impl.mEventData->mPlaceholderFont))
+      {
+        // If the placeholder font is set specifically, only placeholder font is changed.
+        defaultFontDescription = impl.mEventData->mPlaceholderFont->mFontDescription;
+        if(impl.mEventData->mPlaceholderFont->sizeDefined)
+        {
+          defaultPointSize = impl.mEventData->mPlaceholderFont->mDefaultPointSize * impl.mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
+        }
+      }
+      else if(nullptr != impl.mFontDefaults)
+      {
+        // Set the normal font and the placeholder font.
+        defaultFontDescription = impl.mFontDefaults->mFontDescription;
+
+        if(impl.mTextFitEnabled)
+        {
+          defaultPointSize = impl.mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
+        }
+        else
+        {
+          defaultPointSize = impl.mFontDefaults->mDefaultPointSize * impl.mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
+        }
+      }
+
+      // Validates the fonts. If there is a character with no assigned font it sets a default one.
+      // After this call, fonts are validated.
+      multilanguageSupport.ValidateFonts(utf32Characters,
+                                         scripts,
+                                         fontDescriptionRuns,
+                                         defaultFontDescription,
+                                         defaultPointSize,
+                                         startIndex,
+                                         requestedNumberOfCharacters,
+                                         validFonts);
+    }
+    updated = true;
+  }
+
+  Vector<Character> mirroredUtf32Characters;
+  bool              textMirrored       = false;
+  const Length      numberOfParagraphs = impl.mModel->mLogicalModel->mParagraphInfo.Count();
+  if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+  {
+    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = impl.mModel->mLogicalModel->mBidirectionalParagraphInfo;
+    bidirectionalInfo.Reserve(numberOfParagraphs);
+
+    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+    SetBidirectionalInfo(utf32Characters,
+                         scripts,
+                         lineBreakInfo,
+                         startIndex,
+                         requestedNumberOfCharacters,
+                         bidirectionalInfo,
+                         (impl.mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
+                         impl.mLayoutDirection);
+
+    if(0u != bidirectionalInfo.Count())
+    {
+      // Only set the character directions if there is right to left characters.
+      Vector<CharacterDirection>& directions = impl.mModel->mLogicalModel->mCharacterDirections;
+      GetCharactersDirection(bidirectionalInfo,
+                             numberOfCharacters,
+                             startIndex,
+                             requestedNumberOfCharacters,
+                             directions);
+
+      // This paragraph has right to left text. Some characters may need to be mirrored.
+      // TODO: consider if the mirrored string can be stored as well.
+
+      textMirrored = GetMirroredText(utf32Characters,
+                                     directions,
+                                     bidirectionalInfo,
+                                     startIndex,
+                                     requestedNumberOfCharacters,
+                                     mirroredUtf32Characters);
+    }
+    else
+    {
+      // There is no right to left characters. Clear the directions vector.
+      impl.mModel->mLogicalModel->mCharacterDirections.Clear();
+    }
+    updated = true;
+  }
+
+  Vector<GlyphInfo>&      glyphs                = impl.mModel->mVisualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphsToCharactersMap = impl.mModel->mVisualModel->mGlyphsToCharacters;
+  Vector<Length>&         charactersPerGlyph    = impl.mModel->mVisualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex>      newParagraphGlyphs;
+  newParagraphGlyphs.Reserve(numberOfParagraphs);
+
+  const Length currentNumberOfGlyphs = glyphs.Count();
+  if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+  {
+    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+    // Shapes the text.
+    ShapeText(textToShape,
+              lineBreakInfo,
+              scripts,
+              validFonts,
+              startIndex,
+              impl.mTextUpdateInfo.mStartGlyphIndex,
+              requestedNumberOfCharacters,
+              glyphs,
+              glyphsToCharactersMap,
+              charactersPerGlyph,
+              newParagraphGlyphs);
+
+    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+    impl.mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
+    impl.mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, impl.mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
+
+    updated = true;
+  }
+
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+  if(Controller::NO_OPERATION != (Controller::GET_GLYPH_METRICS & operations))
+  {
+    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    impl.mMetrics->GetGlyphMetrics(glyphsBuffer + impl.mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
+
+    // Update the width and advance of all new paragraph characters.
+    for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
+    {
+      const GlyphIndex index = *it;
+      GlyphInfo&       glyph = *(glyphsBuffer + index);
+
+      glyph.xBearing = 0.f;
+      glyph.width    = 0.f;
+      glyph.advance  = 0.f;
+    }
+    updated = true;
+  }
+
+  if((nullptr != impl.mEventData) &&
+      impl.mEventData->mPreEditFlag &&
+     (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count()))
+  {
+    Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
+    impl.mEventData->mInputMethodContext.GetPreeditStyle(attrs);
+    Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
+
+    // Check the type of preedit and run it.
+    for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
+    {
+      Dali::InputMethodContext::PreeditAttributeData attrData = *it;
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
+      type = attrData.preeditType;
+
+      // Check the number of commit characters for the start position.
+      unsigned int numberOfCommit  = impl.mEventData->mPrimaryCursorPosition - impl.mEventData->mPreEditLength;
+      Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
+
+      switch(type)
+      {
+        case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
+        {
+          // Add the underline for the pre-edit text.
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::REVERSE:
+        {
+          Vector4  textColor = impl.mModel->mVisualModel->GetTextColor();
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = textColor;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          Vector4 backgroundColor = impl.mModel->mVisualModel->GetBackgroundColor();
+          if(backgroundColor.a == 0) // There is no text background color.
+          {
+            // Try use the control's background color.
+            if(nullptr != impl.mEditableControlInterface)
+            {
+              impl.mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
+              if(backgroundColor.a == 0) // There is no control background color.
+              {
+                // Determines black or white color according to text color.
+                // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+                float L         = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
+                backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
+              }
+            }
+          }
+
+          Vector<ColorRun> colorRuns;
+          colorRuns.Resize(1u);
+          ColorRun& colorRun                       = *(colorRuns.Begin());
+          colorRun.color                           = backgroundColor;
+          colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          colorRun.characterRun.numberOfCharacters = numberOfIndices;
+          impl.mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
+        {
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = LIGHT_BLUE;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
+        {
+          // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = BACKGROUND_SUB4;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
+        {
+          // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = BACKGROUND_SUB5;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
+        {
+          // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = BACKGROUND_SUB6;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
+        {
+          // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color                           = BACKGROUND_SUB7;
+          impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            impl.CopyUnderlinedFromLogicalToVisualModels(false);
+          }
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::NONE:
+        default:
+        {
+          break;
+        }
+      }
+    }
+    attrs.Clear();
+    updated = true;
+  }
+
+  if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo(impl.mModel->mLogicalModel->mColorRuns,
+                             impl.mModel->mVisualModel->mCharactersToGlyph,
+                             impl.mModel->mVisualModel->mGlyphsPerCharacter,
+                             startIndex,
+                             impl.mTextUpdateInfo.mStartGlyphIndex,
+                             requestedNumberOfCharacters,
+                             impl.mModel->mVisualModel->mColors,
+                             impl.mModel->mVisualModel->mColorIndices);
+
+    // Set the background color runs in glyphs.
+    SetColorSegmentationInfo(impl.mModel->mLogicalModel->mBackgroundColorRuns,
+                             impl.mModel->mVisualModel->mCharactersToGlyph,
+                             impl.mModel->mVisualModel->mGlyphsPerCharacter,
+                             startIndex,
+                             impl.mTextUpdateInfo.mStartGlyphIndex,
+                             requestedNumberOfCharacters,
+                             impl.mModel->mVisualModel->mBackgroundColors,
+                             impl.mModel->mVisualModel->mBackgroundColorIndices);
+
+    updated = true;
+  }
+
+  if((Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations)) &&
+     !((nullptr != impl.mEventData) &&
+         impl.mEventData->mPreEditFlag &&
+       (0u != impl.mModel->mVisualModel->mCharactersToGlyph.Count())))
+  {
+    //Mark-up processor case
+    if(impl.mModel->mVisualModel->IsMarkupProcessorEnabled())
+    {
+      impl.CopyUnderlinedFromLogicalToVisualModels(true);
+    }
+
+    updated = true;
+  }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  impl.mTextUpdateInfo.mEstimatedNumberOfLines = std::max(impl.mModel->mVisualModel->mLines.Count(), impl.mModel->mLogicalModel->mParagraphInfo.Count());
+
+  // Set the previous number of characters for the next time the text is updated.
+  impl.mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
+
+  return updated;
+}
+
+} // namespace Dali::Toolkit::Text
diff --git a/dali-toolkit/internal/text/text-controller-impl-model-updater.h b/dali-toolkit/internal/text/text-controller-impl-model-updater.h
new file mode 100644 (file)
index 0000000..2c5dd8c
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+namespace Dali::Toolkit::Text
+{
+
+/**
+ * Contains methods for updating the models in the TextController
+ */
+struct ControllerImplModelUpdater
+{
+  using OperationsMask = Controller::OperationsMask;
+
+  /**
+   * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
+   *
+   * @param[in] impl A reference to the Controller::Impl class
+   * @param[in] operationsRequired The operations required
+   * @return true if mode has been modified.
+   */
+  static bool Update(Controller::Impl& impl, OperationsMask operationsRequired);
+};
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_MODEL_UPDATER_H
index 045fb8a..2edca46 100644 (file)
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/color-segmentation.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/hyphenator.h>
-#include <dali-toolkit/internal/text/multi-language-support.h>
-#include <dali-toolkit/internal/text/segmentation.h>
-#include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
@@ -60,28 +55,82 @@ struct BackgroundMesh
   Vector<unsigned short>   mIndices;  ///< container of indices
 };
 
-// The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
-// based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
-const float         BRIGHTNESS_THRESHOLD = 0.179f;
-const float         CONSTANT_R           = 0.2126f;
-const float         CONSTANT_G           = 0.7152f;
-const float         CONSTANT_B           = 0.0722f;
-const Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
-const Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
-const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
-
 } // namespace
 
-namespace Dali
+namespace Dali::Toolkit::Text
 {
-namespace Toolkit
+
+namespace
 {
-namespace Text
+
+void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
 {
+  // Sets the default text's color.
+  inputStyle.textColor      = textColor;
+  inputStyle.isDefaultColor = true;
+
+  inputStyle.familyName.clear();
+  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+  inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
+  inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
+  inputStyle.size   = 0.f;
+
+  inputStyle.lineSpacing = 0.f;
+
+  inputStyle.underlineProperties.clear();
+  inputStyle.shadowProperties.clear();
+  inputStyle.embossProperties.clear();
+  inputStyle.outlineProperties.clear();
+
+  inputStyle.isFamilyDefined = false;
+  inputStyle.isWeightDefined = false;
+  inputStyle.isWidthDefined  = false;
+  inputStyle.isSlantDefined  = false;
+  inputStyle.isSizeDefined   = false;
+
+  inputStyle.isLineSpacingDefined = false;
+
+  inputStyle.isUnderlineDefined = false;
+  inputStyle.isShadowDefined    = false;
+  inputStyle.isEmbossDefined    = false;
+  inputStyle.isOutlineDefined   = false;
+
+  // Sets the default font's family name, weight, width, slant and size.
+  if(fontDefaults)
+  {
+    if(fontDefaults->familyDefined)
+    {
+      inputStyle.familyName      = fontDefaults->mFontDescription.family;
+      inputStyle.isFamilyDefined = true;
+    }
+
+    if(fontDefaults->weightDefined)
+    {
+      inputStyle.weight          = fontDefaults->mFontDescription.weight;
+      inputStyle.isWeightDefined = true;
+    }
+
+    if(fontDefaults->widthDefined)
+    {
+      inputStyle.width          = fontDefaults->mFontDescription.width;
+      inputStyle.isWidthDefined = true;
+    }
+
+    if(fontDefaults->slantDefined)
+    {
+      inputStyle.slant          = fontDefaults->mFontDescription.slant;
+      inputStyle.isSlantDefined = true;
+    }
+
+    if(fontDefaults->sizeDefined)
+    {
+      inputStyle.size          = fontDefaults->mDefaultPointSize;
+      inputStyle.isSizeDefined = true;
+    }
+  }
+}
+} // unnamed Namespace
+
 EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
 : mDecorator(decorator),
   mInputMethodContext(inputMethodContext),
@@ -588,600 +637,12 @@ void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex
 
 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
-
-  // Calculate the operations to be done.
-  const OperationsMask operations = static_cast<OperationsMask>(mOperationsPending & operationsRequired);
-
-  if(NO_OPERATION == operations)
-  {
-    // Nothing to do if no operations are pending and required.
-    return false;
-  }
-
-  Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
-  Vector<Character>  displayCharacters;
-  bool               useHiddenText = false;
-  if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
-  {
-    mHiddenInput->Substitute(srcCharacters, displayCharacters);
-    useHiddenText = true;
-  }
-
-  Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
-  const Length       numberOfCharacters = utf32Characters.Count();
-
-  // Index to the first character of the first paragraph to be updated.
-  CharacterIndex startIndex = 0u;
-  // Number of characters of the paragraphs to be removed.
-  Length paragraphCharacters = 0u;
-
-  CalculateTextUpdateIndices(paragraphCharacters);
-
-  // Check whether the indices for updating the text is valid
-  if(numberOfCharacters > 0u &&
-     (mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
-      mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
-  {
-    std::string currentText;
-    Utf32ToUtf8(mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
-
-    DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
-    DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
-
-    // Dump mTextUpdateInfo
-    DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
-    DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph);
-
-    return false;
-  }
-
-  startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
-
-  if(mTextUpdateInfo.mClearAll ||
-     (0u != paragraphCharacters))
-  {
-    ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
-  }
-
-  mTextUpdateInfo.mClearAll = false;
-
-  // Whether the model is updated.
-  bool updated = false;
-
-  Vector<LineBreakInfo>& lineBreakInfo               = mModel->mLogicalModel->mLineBreakInfo;
-  const Length           requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
-
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
-    // calculate the bidirectional info for each 'paragraph'.
-    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
-    // is not shaped together).
-    lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
-
-    SetLineBreakInfo(utf32Characters,
-                     startIndex,
-                     requestedNumberOfCharacters,
-                     lineBreakInfo);
-
-    if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
-       mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
-    {
-      CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
-      LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-
-      for(CharacterIndex index = startIndex; index < end; index++)
-      {
-        CharacterIndex wordEnd = index;
-        while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
-        {
-          wordEnd++;
-        }
-
-        if((wordEnd + 1) == end) // add last char
-        {
-          wordEnd++;
-        }
-
-        Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
-
-        for(CharacterIndex i = 0; i < (wordEnd - index); i++)
-        {
-          if(hyphens[i])
-          {
-            *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
-          }
-        }
-
-        index = wordEnd;
-      }
-    }
-
-    // Create the paragraph info.
-    mModel->mLogicalModel->CreateParagraphInfo(startIndex,
-                                               requestedNumberOfCharacters);
-    updated = true;
-  }
-
-  const bool getScripts    = NO_OPERATION != (GET_SCRIPTS & operations);
-  const bool validateFonts = NO_OPERATION != (VALIDATE_FONTS & operations);
-
-  Vector<ScriptRun>& scripts    = mModel->mLogicalModel->mScriptRuns;
-  Vector<FontRun>&   validFonts = mModel->mLogicalModel->mFontRuns;
-
-  if(getScripts || validateFonts)
-  {
-    // Validates the fonts assigned by the application or assigns default ones.
-    // It makes sure all the characters are going to be rendered by the correct font.
-    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-
-    if(getScripts)
-    {
-      // Retrieves the scripts used in the text.
-      multilanguageSupport.SetScripts(utf32Characters,
-                                      startIndex,
-                                      requestedNumberOfCharacters,
-                                      scripts);
-    }
-
-    if(validateFonts)
-    {
-      // Validate the fonts set through the mark-up string.
-      Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
-
-      // Get the default font's description.
-      TextAbstraction::FontDescription defaultFontDescription;
-      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
-
-      //Get the number of points per one unit of point-size
-      uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
-
-      if(IsShowingPlaceholderText() && mEventData && (nullptr != mEventData->mPlaceholderFont))
-      {
-        // If the placeholder font is set specifically, only placeholder font is changed.
-        defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
-        if(mEventData->mPlaceholderFont->sizeDefined)
-        {
-          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
-        }
-      }
-      else if(nullptr != mFontDefaults)
-      {
-        // Set the normal font and the placeholder font.
-        defaultFontDescription = mFontDefaults->mFontDescription;
-
-        if(mTextFitEnabled)
-        {
-          defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
-        }
-        else
-        {
-          defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
-        }
-      }
-
-      // Validates the fonts. If there is a character with no assigned font it sets a default one.
-      // After this call, fonts are validated.
-      multilanguageSupport.ValidateFonts(utf32Characters,
-                                         scripts,
-                                         fontDescriptionRuns,
-                                         defaultFontDescription,
-                                         defaultPointSize,
-                                         startIndex,
-                                         requestedNumberOfCharacters,
-                                         validFonts);
-    }
-    updated = true;
-  }
-
-  Vector<Character> mirroredUtf32Characters;
-  bool              textMirrored       = false;
-  const Length      numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
-  if(NO_OPERATION != (BIDI_INFO & operations))
-  {
-    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
-    bidirectionalInfo.Reserve(numberOfParagraphs);
-
-    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
-    SetBidirectionalInfo(utf32Characters,
-                         scripts,
-                         lineBreakInfo,
-                         startIndex,
-                         requestedNumberOfCharacters,
-                         bidirectionalInfo,
-                         (mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
-                         mLayoutDirection);
-
-    if(0u != bidirectionalInfo.Count())
-    {
-      // Only set the character directions if there is right to left characters.
-      Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
-      GetCharactersDirection(bidirectionalInfo,
-                             numberOfCharacters,
-                             startIndex,
-                             requestedNumberOfCharacters,
-                             directions);
-
-      // This paragraph has right to left text. Some characters may need to be mirrored.
-      // TODO: consider if the mirrored string can be stored as well.
-
-      textMirrored = GetMirroredText(utf32Characters,
-                                     directions,
-                                     bidirectionalInfo,
-                                     startIndex,
-                                     requestedNumberOfCharacters,
-                                     mirroredUtf32Characters);
-    }
-    else
-    {
-      // There is no right to left characters. Clear the directions vector.
-      mModel->mLogicalModel->mCharacterDirections.Clear();
-    }
-    updated = true;
-  }
-
-  Vector<GlyphInfo>&      glyphs                = mModel->mVisualModel->mGlyphs;
-  Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
-  Vector<Length>&         charactersPerGlyph    = mModel->mVisualModel->mCharactersPerGlyph;
-  Vector<GlyphIndex>      newParagraphGlyphs;
-  newParagraphGlyphs.Reserve(numberOfParagraphs);
-
-  const Length currentNumberOfGlyphs = glyphs.Count();
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
-    // Shapes the text.
-    ShapeText(textToShape,
-              lineBreakInfo,
-              scripts,
-              validFonts,
-              startIndex,
-              mTextUpdateInfo.mStartGlyphIndex,
-              requestedNumberOfCharacters,
-              glyphs,
-              glyphsToCharactersMap,
-              charactersPerGlyph,
-              newParagraphGlyphs);
-
-    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
-    mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
-
-    updated = true;
-  }
-
-  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
-
-  if(NO_OPERATION != (GET_GLYPH_METRICS & operations))
-  {
-    GlyphInfo* glyphsBuffer = glyphs.Begin();
-    mMetrics->GetGlyphMetrics(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
-
-    // Update the width and advance of all new paragraph characters.
-    for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
-    {
-      const GlyphIndex index = *it;
-      GlyphInfo&       glyph = *(glyphsBuffer + index);
-
-      glyph.xBearing = 0.f;
-      glyph.width    = 0.f;
-      glyph.advance  = 0.f;
-    }
-    updated = true;
-  }
-
-  if((nullptr != mEventData) &&
-     mEventData->mPreEditFlag &&
-     (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
-  {
-    Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
-    mEventData->mInputMethodContext.GetPreeditStyle(attrs);
-    Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
-
-    // Check the type of preedit and run it.
-    for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
-    {
-      Dali::InputMethodContext::PreeditAttributeData attrData = *it;
-      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
-      type = attrData.preeditType;
-
-      // Check the number of commit characters for the start position.
-      unsigned int numberOfCommit  = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
-      Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
-
-      switch(type)
-      {
-        case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
-        {
-          // Add the underline for the pre-edit text.
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::REVERSE:
-        {
-          Vector4  textColor = mModel->mVisualModel->GetTextColor();
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = textColor;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
-          if(backgroundColor.a == 0) // There is no text background color.
-          {
-            // Try use the control's background color.
-            if(nullptr != mEditableControlInterface)
-            {
-              mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
-              if(backgroundColor.a == 0) // There is no control background color.
-              {
-                // Determines black or white color according to text color.
-                // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
-                float L         = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
-                backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
-              }
-            }
-          }
-
-          Vector<ColorRun> colorRuns;
-          colorRuns.Resize(1u);
-          ColorRun& colorRun                       = *(colorRuns.Begin());
-          colorRun.color                           = backgroundColor;
-          colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          colorRun.characterRun.numberOfCharacters = numberOfIndices;
-          mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
-        {
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = LIGHT_BLUE;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
-        {
-          // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB4;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
-        {
-          // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB5;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
-        {
-          // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB6;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
-        {
-          // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB7;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::NONE:
-        default:
-        {
-          break;
-        }
-      }
-    }
-    attrs.Clear();
-    updated = true;
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    // Set the color runs in glyphs.
-    SetColorSegmentationInfo(mModel->mLogicalModel->mColorRuns,
-                             mModel->mVisualModel->mCharactersToGlyph,
-                             mModel->mVisualModel->mGlyphsPerCharacter,
-                             startIndex,
-                             mTextUpdateInfo.mStartGlyphIndex,
-                             requestedNumberOfCharacters,
-                             mModel->mVisualModel->mColors,
-                             mModel->mVisualModel->mColorIndices);
-
-    // Set the background color runs in glyphs.
-    SetColorSegmentationInfo(mModel->mLogicalModel->mBackgroundColorRuns,
-                             mModel->mVisualModel->mCharactersToGlyph,
-                             mModel->mVisualModel->mGlyphsPerCharacter,
-                             startIndex,
-                             mTextUpdateInfo.mStartGlyphIndex,
-                             requestedNumberOfCharacters,
-                             mModel->mVisualModel->mBackgroundColors,
-                             mModel->mVisualModel->mBackgroundColorIndices);
-
-    updated = true;
-  }
-
-  if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
-     !((nullptr != mEventData) &&
-       mEventData->mPreEditFlag &&
-       (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
-  {
-    //Mark-up processor case
-    if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-    {
-      CopyUnderlinedFromLogicalToVisualModels(true);
-    }
-
-    updated = true;
-  }
-
-  // The estimated number of lines. Used to avoid reallocations when layouting.
-  mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
-
-  // Set the previous number of characters for the next time the text is updated.
-  mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-
-  return updated;
+  return ControllerImplModelUpdater::Update(*this, operationsRequired);
 }
 
 void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
 {
-  // Sets the default text's color.
-  inputStyle.textColor      = mTextColor;
-  inputStyle.isDefaultColor = true;
-
-  inputStyle.familyName.clear();
-  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
-  inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
-  inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
-  inputStyle.size   = 0.f;
-
-  inputStyle.lineSpacing = 0.f;
-
-  inputStyle.underlineProperties.clear();
-  inputStyle.shadowProperties.clear();
-  inputStyle.embossProperties.clear();
-  inputStyle.outlineProperties.clear();
-
-  inputStyle.isFamilyDefined = false;
-  inputStyle.isWeightDefined = false;
-  inputStyle.isWidthDefined  = false;
-  inputStyle.isSlantDefined  = false;
-  inputStyle.isSizeDefined   = false;
-
-  inputStyle.isLineSpacingDefined = false;
-
-  inputStyle.isUnderlineDefined = false;
-  inputStyle.isShadowDefined    = false;
-  inputStyle.isEmbossDefined    = false;
-  inputStyle.isOutlineDefined   = false;
-
-  // Sets the default font's family name, weight, width, slant and size.
-  if(mFontDefaults)
-  {
-    if(mFontDefaults->familyDefined)
-    {
-      inputStyle.familyName      = mFontDefaults->mFontDescription.family;
-      inputStyle.isFamilyDefined = true;
-    }
-
-    if(mFontDefaults->weightDefined)
-    {
-      inputStyle.weight          = mFontDefaults->mFontDescription.weight;
-      inputStyle.isWeightDefined = true;
-    }
-
-    if(mFontDefaults->widthDefined)
-    {
-      inputStyle.width          = mFontDefaults->mFontDescription.width;
-      inputStyle.isWidthDefined = true;
-    }
-
-    if(mFontDefaults->slantDefined)
-    {
-      inputStyle.slant          = mFontDefaults->mFontDescription.slant;
-      inputStyle.isSlantDefined = true;
-    }
-
-    if(mFontDefaults->sizeDefined)
-    {
-      inputStyle.size          = mFontDefaults->mDefaultPointSize;
-      inputStyle.isSizeDefined = true;
-    }
-  }
+  SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
 }
 
 float Controller::Impl::GetDefaultFontLineHeight()
@@ -2125,7 +1586,7 @@ Actor Controller::Impl::CreateBackgroundActor()
 
     const Vector2 textSize = mView.GetLayoutSize();
 
-    const float offsetX = textSize.width * 0.5f;
+    const float offsetX = alignmentOffset + textSize.width * 0.5f;
     const float offsetY = textSize.height * 0.5f;
 
     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
@@ -2297,8 +1758,4 @@ void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearP
   }
 }
 
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+} // namespace Dali::Toolkit::Text
index 02fbff8..0c6297f 100644 (file)
@@ -46,6 +46,7 @@ const float DEFAULT_FONT_SIZE_SCALE = 1.f;
 struct CursorInfo;
 struct FontDefaults;
 struct ControllerImplEventHandler;
+struct ControllerImplModelUpdater;
 struct SelectionHandleController;
 
 class SelectableControlInterface;
@@ -845,6 +846,7 @@ public:
 
 private:
   friend ControllerImplEventHandler;
+  friend ControllerImplModelUpdater;
   friend SelectionHandleController;
 };
 
index 30c6e04..6e4d361 100644 (file)
@@ -46,48 +46,76 @@ constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
 
 const std::string EMPTY_STRING("");
 
-int ConvertPixelToPint(float pixel)
+template<typename Type>
+void EnsureCreated(Type*& object)
 {
-  unsigned int                      horizontalDpi = 0u;
-  unsigned int                      verticalDpi   = 0u;
-  Dali::TextAbstraction::FontClient fontClient    = Dali::TextAbstraction::FontClient::Get();
-  fontClient.GetDpi(horizontalDpi, verticalDpi);
-
-  return (pixel * 72.f) / static_cast<float>(horizontalDpi);
+  if(!object)
+  {
+    object = new Type();
+  }
 }
 
-} // namespace
+template<typename Type>
+void EnsureCreated(std::unique_ptr<Type>& object)
+{
+  if(!object)
+  {
+    object = std::unique_ptr<Type>(new Type());
+  }
+}
 
-namespace Dali
+template<typename Type, typename Arg1>
+void EnsureCreated(Type*& object, Arg1 arg1)
 {
-namespace Toolkit
+  if(!object)
+  {
+    object = new Type(arg1);
+  }
+}
+
+template<typename Type, typename Arg1, typename Arg2>
+void EnsureCreated(Type*& object, Arg1 arg1, Arg2 arg2)
 {
-namespace Text
+  if(!object)
+  {
+    object = new Type(arg1, arg2);
+  }
+}
+
+float GetDpi()
 {
-// public : Constructor.
+  unsigned int                      horizontalDpi = 0u;
+  unsigned int                      verticalDpi   = 0u;
+  Dali::TextAbstraction::FontClient fontClient    = Dali::TextAbstraction::FontClient::Get();
+  fontClient.GetDpi(horizontalDpi, verticalDpi);
+  return static_cast<float>(horizontalDpi);
+}
 
-ControllerPtr Controller::New()
+float ConvertPixelToPoint(float pixel)
 {
-  return ControllerPtr(new Controller());
+  return pixel * 72.0f / GetDpi();
 }
 
-ControllerPtr Controller::New(ControlInterface* controlInterface)
+float ConvertPointToPixel(float point)
 {
-  return ControllerPtr(new Controller(controlInterface));
+  // Pixel size = Point size * DPI / 72.f
+  return point * GetDpi() / 72.0f;
 }
 
-ControllerPtr Controller::New(ControlInterface*           controlInterface,
-                              EditableControlInterface*   editableControlInterface,
-                              SelectableControlInterface* selectableControlInterface,
-                              AnchorControlInterface*     anchorControlInterface)
+void UpdateCursorPosition(Dali::Toolkit::Text::EventData* eventData)
 {
-  return ControllerPtr(new Controller(controlInterface,
-                                      editableControlInterface,
-                                      selectableControlInterface,
-                                      anchorControlInterface));
+  if(eventData && Dali::Toolkit::Text::EventData::IsEditingState(eventData->mState))
+  {
+    // Update the cursor position if it's in editing mode
+    eventData->mDecoratorUpdated     = true;
+    eventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
+  }
 }
 
-// public : Configure the text controller.
+} // namespace
+
+namespace Dali::Toolkit::Text
+{
 
 void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
 {
@@ -100,10 +128,7 @@ void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inp
     return;
   }
 
-  if(NULL == mImpl->mEventData)
-  {
-    mImpl->mEventData = new EventData(decorator, inputMethodContext);
-  }
+  EnsureCreated(mImpl->mEventData, decorator, inputMethodContext);
 }
 
 void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
@@ -147,24 +172,20 @@ void Controller::SetAutoScrollEnabled(bool enable)
 
   if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
   {
+    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
+                                                            LAYOUT |
+                                                            ALIGN |
+                                                            UPDATE_LAYOUT_SIZE |
+                                                            REORDER);
+
     if(enable)
     {
       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
-      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
-                                                              LAYOUT |
-                                                              ALIGN |
-                                                              UPDATE_LAYOUT_SIZE |
-                                                              UPDATE_DIRECTION |
-                                                              REORDER);
+      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | UPDATE_DIRECTION);
     }
     else
     {
       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
-      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
-                                                              LAYOUT |
-                                                              ALIGN |
-                                                              UPDATE_LAYOUT_SIZE |
-                                                              REORDER);
     }
 
     mImpl->mIsAutoScrollEnabled = enable;
@@ -192,62 +213,42 @@ CharacterDirection Controller::GetAutoScrollDirection() const
 float Controller::GetAutoScrollLineAlignment() const
 {
   float offset = 0.f;
-
-  if(mImpl->mModel->mVisualModel &&
-     (0u != mImpl->mModel->mVisualModel->mLines.Count()))
+  if(mImpl->mModel->mVisualModel && (0u != mImpl->mModel->mVisualModel->mLines.Count()))
   {
     offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
   }
-
   return offset;
 }
 
 void Controller::SetHorizontalScrollEnabled(bool enable)
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
+  if(mImpl->mEventData && mImpl->mEventData->mDecorator)
   {
     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
   }
 }
+
 bool Controller::IsHorizontalScrollEnabled() const
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
-  {
-    return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
-  }
-
-  return false;
+  return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
 }
 
 void Controller::SetVerticalScrollEnabled(bool enable)
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
+  if(mImpl->mEventData && mImpl->mEventData->mDecorator)
   {
-    if(mImpl->mEventData->mDecorator)
-    {
-      mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
-    }
+    mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
   }
 }
 
 bool Controller::IsVerticalScrollEnabled() const
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
-  {
-    return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
-  }
-
-  return false;
+  return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
 }
 
 void Controller::SetSmoothHandlePanEnabled(bool enable)
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
+  if(mImpl->mEventData && mImpl->mEventData->mDecorator)
   {
     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
   }
@@ -255,13 +256,7 @@ void Controller::SetSmoothHandlePanEnabled(bool enable)
 
 bool Controller::IsSmoothHandlePanEnabled() const
 {
-  if((NULL != mImpl->mEventData) &&
-     mImpl->mEventData->mDecorator)
-  {
-    return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
-  }
-
-  return false;
+  return mImpl->mEventData && mImpl->mEventData->mDecorator && mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
 }
 
 void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
@@ -278,12 +273,11 @@ void Controller::SetEnableCursorBlink(bool enable)
 {
   DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled");
 
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mCursorBlinkEnabled = enable;
 
-    if(!enable &&
-       mImpl->mEventData->mDecorator)
+    if(!enable && mImpl->mEventData->mDecorator)
     {
       mImpl->mEventData->mDecorator->StopCursorBlink();
     }
@@ -292,12 +286,7 @@ void Controller::SetEnableCursorBlink(bool enable)
 
 bool Controller::GetEnableCursorBlink() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mCursorBlinkEnabled;
-  }
-
-  return false;
+  return mImpl->mEventData && mImpl->mEventData->mCursorBlinkEnabled;
 }
 
 void Controller::SetMultiLineEnabled(bool enable)
@@ -367,9 +356,7 @@ void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
   {
     // Set the alignment.
     mImpl->mModel->mVerticalAlignment = alignment;
-
     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
-
     mImpl->RequestRelayout();
   }
 }
@@ -484,19 +471,7 @@ bool Controller::IsTextFitEnabled() const
 
 void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
 {
-  switch(type)
-  {
-    case POINT_SIZE:
-    {
-      mImpl->mTextFitMinSize = minSize;
-      break;
-    }
-    case PIXEL_SIZE:
-    {
-      mImpl->mTextFitMinSize = ConvertPixelToPint(minSize);
-      break;
-    }
-  }
+  mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
 }
 
 float Controller::GetTextFitMinSize() const
@@ -506,19 +481,7 @@ float Controller::GetTextFitMinSize() const
 
 void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
 {
-  switch(type)
-  {
-    case POINT_SIZE:
-    {
-      mImpl->mTextFitMaxSize = maxSize;
-      break;
-    }
-    case PIXEL_SIZE:
-    {
-      mImpl->mTextFitMaxSize = ConvertPixelToPint(maxSize);
-      break;
-    }
-  }
+  mImpl->mTextFitMaxSize = (type == POINT_SIZE) ? maxSize : ConvertPixelToPoint(maxSize);
 }
 
 float Controller::GetTextFitMaxSize() const
@@ -528,19 +491,7 @@ float Controller::GetTextFitMaxSize() const
 
 void Controller::SetTextFitStepSize(float step, FontSizeType type)
 {
-  switch(type)
-  {
-    case POINT_SIZE:
-    {
-      mImpl->mTextFitStepSize = step;
-      break;
-    }
-    case PIXEL_SIZE:
-    {
-      mImpl->mTextFitStepSize = ConvertPixelToPint(step);
-      break;
-    }
-  }
+  mImpl->mTextFitStepSize = (type == POINT_SIZE) ? step : ConvertPixelToPoint(step);
 }
 
 float Controller::GetTextFitStepSize() const
@@ -608,8 +559,6 @@ bool Controller::IsGrabHandlePopupEnabled() const
   return mImpl->mEventData->mGrabHandlePopupEnabled;
 }
 
-// public : Update
-
 void Controller::SetText(const std::string& text)
 {
   TextUpdater::SetText(*this, text);
@@ -678,28 +627,16 @@ void Controller::SendSelectionToClipboard(bool deleteAfterSending)
   mImpl->SendSelectionToClipboard(deleteAfterSending);
 }
 
-// public : Default style & Input style
-
 void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
 {
-  if(NULL == mImpl->mFontDefaults)
-  {
-    mImpl->mFontDefaults = new FontDefaults();
-  }
+  EnsureCreated(mImpl->mFontDefaults);
 
   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -709,12 +646,7 @@ void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
 
 const std::string& Controller::GetDefaultFontFamily() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->mFontDescription.family;
-  }
-
-  return EMPTY_STRING;
+  return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.family : EMPTY_STRING;
 }
 
 void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
@@ -729,23 +661,13 @@ const std::string& Controller::GetPlaceholderFontFamily() const
 
 void Controller::SetDefaultFontWeight(FontWeight weight)
 {
-  if(NULL == mImpl->mFontDefaults)
-  {
-    mImpl->mFontDefaults = new FontDefaults();
-  }
+  EnsureCreated(mImpl->mFontDefaults);
 
   mImpl->mFontDefaults->mFontDescription.weight = weight;
   mImpl->mFontDefaults->weightDefined           = true;
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -755,22 +677,12 @@ void Controller::SetDefaultFontWeight(FontWeight weight)
 
 bool Controller::IsDefaultFontWeightDefined() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->weightDefined;
-  }
-
-  return false;
+  return mImpl->mFontDefaults && mImpl->mFontDefaults->weightDefined;
 }
 
 FontWeight Controller::GetDefaultFontWeight() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->mFontDescription.weight;
-  }
-
-  return TextAbstraction::FontWeight::NORMAL;
+  return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.weight : TextAbstraction::FontWeight::NORMAL;
 }
 
 void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
@@ -781,7 +693,6 @@ void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
 bool Controller::IsPlaceholderTextFontWeightDefined() const
 {
   return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
-  ;
 }
 
 FontWeight Controller::GetPlaceholderTextFontWeight() const
@@ -791,23 +702,13 @@ FontWeight Controller::GetPlaceholderTextFontWeight() const
 
 void Controller::SetDefaultFontWidth(FontWidth width)
 {
-  if(NULL == mImpl->mFontDefaults)
-  {
-    mImpl->mFontDefaults = new FontDefaults();
-  }
+  EnsureCreated(mImpl->mFontDefaults);
 
   mImpl->mFontDefaults->mFontDescription.width = width;
   mImpl->mFontDefaults->widthDefined           = true;
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -817,22 +718,12 @@ void Controller::SetDefaultFontWidth(FontWidth width)
 
 bool Controller::IsDefaultFontWidthDefined() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->widthDefined;
-  }
-
-  return false;
+  return mImpl->mFontDefaults && mImpl->mFontDefaults->widthDefined;
 }
 
 FontWidth Controller::GetDefaultFontWidth() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->mFontDescription.width;
-  }
-
-  return TextAbstraction::FontWidth::NORMAL;
+  return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.width : TextAbstraction::FontWidth::NORMAL;
 }
 
 void Controller::SetPlaceholderTextFontWidth(FontWidth width)
@@ -852,23 +743,13 @@ FontWidth Controller::GetPlaceholderTextFontWidth() const
 
 void Controller::SetDefaultFontSlant(FontSlant slant)
 {
-  if(NULL == mImpl->mFontDefaults)
-  {
-    mImpl->mFontDefaults = new FontDefaults();
-  }
+  EnsureCreated(mImpl->mFontDefaults);
 
   mImpl->mFontDefaults->mFontDescription.slant = slant;
   mImpl->mFontDefaults->slantDefined           = true;
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -878,21 +759,12 @@ void Controller::SetDefaultFontSlant(FontSlant slant)
 
 bool Controller::IsDefaultFontSlantDefined() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->slantDefined;
-  }
-  return false;
+  return mImpl->mFontDefaults && mImpl->mFontDefaults->slantDefined;
 }
 
 FontSlant Controller::GetDefaultFontSlant() const
 {
-  if(NULL != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontDefaults->mFontDescription.slant;
-  }
-
-  return TextAbstraction::FontSlant::NORMAL;
+  return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFontDescription.slant : TextAbstraction::FontSlant::NORMAL;
 }
 
 void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
@@ -914,15 +786,8 @@ void Controller::SetFontSizeScale(float scale)
 {
   mImpl->mFontSizeScale = scale;
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -932,52 +797,18 @@ void Controller::SetFontSizeScale(float scale)
 
 float Controller::GetFontSizeScale() const
 {
-  if(nullptr != mImpl->mFontDefaults)
-  {
-    return mImpl->mFontSizeScale;
-  }
-
-  return 1.f;
+  return mImpl->mFontDefaults ? mImpl->mFontSizeScale : 1.0f;
 }
 
 void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
 {
-  if(NULL == mImpl->mFontDefaults)
-  {
-    mImpl->mFontDefaults = new FontDefaults();
-  }
+  EnsureCreated(mImpl->mFontDefaults);
 
-  switch(type)
-  {
-    case POINT_SIZE:
-    {
-      mImpl->mFontDefaults->mDefaultPointSize = fontSize;
-      mImpl->mFontDefaults->sizeDefined       = true;
-      break;
-    }
-    case PIXEL_SIZE:
-    {
-      // Point size = Pixel size * 72.f / DPI
-      unsigned int                horizontalDpi = 0u;
-      unsigned int                verticalDpi   = 0u;
-      TextAbstraction::FontClient fontClient    = TextAbstraction::FontClient::Get();
-      fontClient.GetDpi(horizontalDpi, verticalDpi);
-
-      mImpl->mFontDefaults->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
-      mImpl->mFontDefaults->sizeDefined       = true;
-      break;
-    }
-  }
+  mImpl->mFontDefaults->mDefaultPointSize = (type == POINT_SIZE) ? fontSize : ConvertPixelToPoint(fontSize);
+  mImpl->mFontDefaults->sizeDefined       = true;
 
-  if(mImpl->mEventData)
-  {
-    // Update the cursor position if it's in editing mode
-    if(EventData::IsEditingState(mImpl->mEventData->mState))
-    {
-      mImpl->mEventData->mDecoratorUpdated     = true;
-      mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
-    }
-  }
+  // Update the cursor position if it's in editing mode
+  UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
   ClearFontData();
@@ -987,32 +818,11 @@ void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
 
 float Controller::GetDefaultFontSize(FontSizeType type) const
 {
-  float value = 0.0f;
-  if(NULL != mImpl->mFontDefaults)
+  if(mImpl->mFontDefaults)
   {
-    switch(type)
-    {
-      case POINT_SIZE:
-      {
-        value = mImpl->mFontDefaults->mDefaultPointSize;
-        break;
-      }
-      case PIXEL_SIZE:
-      {
-        // Pixel size = Point size * DPI / 72.f
-        unsigned int                horizontalDpi = 0u;
-        unsigned int                verticalDpi   = 0u;
-        TextAbstraction::FontClient fontClient    = TextAbstraction::FontClient::Get();
-        fontClient.GetDpi(horizontalDpi, verticalDpi);
-
-        value = mImpl->mFontDefaults->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
-        break;
-      }
-    }
-    return value;
+    return (type == POINT_SIZE) ? mImpl->mFontDefaults->mDefaultPointSize : ConvertPointToPixel(mImpl->mFontDefaults->mDefaultPointSize);
   }
-
-  return value;
+  return 0.0f;
 }
 
 void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
@@ -1032,11 +842,8 @@ void Controller::SetDefaultColor(const Vector4& color)
   if(!mImpl->IsShowingPlaceholderText())
   {
     mImpl->mModel->mVisualModel->SetTextColor(color);
-
     mImpl->mModel->mLogicalModel->mColorRuns.Clear();
-
     mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
-
     mImpl->RequestRelayout();
   }
 }
@@ -1059,7 +866,6 @@ const Vector4& Controller::GetPlaceholderTextColor() const
 void Controller::SetShadowOffset(const Vector2& shadowOffset)
 {
   mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
-
   mImpl->RequestRelayout();
 }
 
@@ -1071,7 +877,6 @@ const Vector2& Controller::GetShadowOffset() const
 void Controller::SetShadowColor(const Vector4& shadowColor)
 {
   mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
-
   mImpl->RequestRelayout();
 }
 
@@ -1085,7 +890,6 @@ void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
   if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
   {
     mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
-
     mImpl->RequestRelayout();
   }
 }
@@ -1098,7 +902,6 @@ const float& Controller::GetShadowBlurRadius() const
 void Controller::SetUnderlineColor(const Vector4& color)
 {
   mImpl->mModel->mVisualModel->SetUnderlineColor(color);
-
   mImpl->RequestRelayout();
 }
 
@@ -1110,7 +913,6 @@ const Vector4& Controller::GetUnderlineColor() const
 void Controller::SetUnderlineEnabled(bool enabled)
 {
   mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
-
   mImpl->RequestRelayout();
 }
 
@@ -1122,7 +924,6 @@ bool Controller::IsUnderlineEnabled() const
 void Controller::SetUnderlineHeight(float height)
 {
   mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
-
   mImpl->RequestRelayout();
 }
 
@@ -1134,7 +935,6 @@ float Controller::GetUnderlineHeight() const
 void Controller::SetOutlineColor(const Vector4& color)
 {
   mImpl->mModel->mVisualModel->SetOutlineColor(color);
-
   mImpl->RequestRelayout();
 }
 
@@ -1146,7 +946,6 @@ const Vector4& Controller::GetOutlineColor() const
 void Controller::SetOutlineWidth(uint16_t width)
 {
   mImpl->mModel->mVisualModel->SetOutlineWidth(width);
-
   mImpl->RequestRelayout();
 }
 
@@ -1158,7 +957,6 @@ uint16_t Controller::GetOutlineWidth() const
 void Controller::SetBackgroundColor(const Vector4& color)
 {
   mImpl->mModel->mVisualModel->SetBackgroundColor(color);
-
   mImpl->RequestRelayout();
 }
 
@@ -1170,7 +968,6 @@ const Vector4& Controller::GetBackgroundColor() const
 void Controller::SetBackgroundEnabled(bool enabled)
 {
   mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
-
   mImpl->RequestRelayout();
 }
 
@@ -1181,42 +978,24 @@ bool Controller::IsBackgroundEnabled() const
 
 void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
 {
-  if(NULL == mImpl->mEmbossDefaults)
-  {
-    mImpl->mEmbossDefaults = new EmbossDefaults();
-  }
-
+  EnsureCreated(mImpl->mEmbossDefaults);
   mImpl->mEmbossDefaults->properties = embossProperties;
 }
 
 const std::string& Controller::GetDefaultEmbossProperties() const
 {
-  if(NULL != mImpl->mEmbossDefaults)
-  {
-    return mImpl->mEmbossDefaults->properties;
-  }
-
-  return EMPTY_STRING;
+  return mImpl->mEmbossDefaults ? mImpl->mEmbossDefaults->properties : EMPTY_STRING;
 }
 
 void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
 {
-  if(NULL == mImpl->mOutlineDefaults)
-  {
-    mImpl->mOutlineDefaults = new OutlineDefaults();
-  }
-
+  EnsureCreated(mImpl->mOutlineDefaults);
   mImpl->mOutlineDefaults->properties = outlineProperties;
 }
 
 const std::string& Controller::GetDefaultOutlineProperties() const
 {
-  if(NULL != mImpl->mOutlineDefaults)
-  {
-    return mImpl->mOutlineDefaults->properties;
-  }
-
-  return EMPTY_STRING;
+  return mImpl->mOutlineDefaults ? mImpl->mOutlineDefaults->properties : EMPTY_STRING;
 }
 
 void Controller::RelayoutForNewLineSize()
@@ -1228,7 +1007,7 @@ void Controller::RelayoutForNewLineSize()
   mImpl->mOperationsPending                          = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
 
   //remove selection
-  if((mImpl->mEventData != nullptr) && (mImpl->mEventData->mState == EventData::SELECTING))
+  if(mImpl->mEventData && mImpl->mEventData->mState == EventData::SELECTING)
   {
     mImpl->ChangeState(EventData::EDITING);
   }
@@ -1274,7 +1053,7 @@ float Controller::GetDefaultLineSize() const
 
 void Controller::SetInputColor(const Vector4& color)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.textColor      = color;
     mImpl->mEventData->mInputStyle.isDefaultColor = false;
@@ -1318,13 +1097,8 @@ void Controller::SetInputColor(const Vector4& color)
 
 const Vector4& Controller::GetInputColor() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.textColor;
-  }
-
-  // Return the default text's color if there is no EventData.
-  return mImpl->mTextColor;
+  // Return event text input color if we have it, otherwise just return the default text's color
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.textColor : mImpl->mTextColor;
 }
 
 void Controller::SetInputFontFamily(const std::string& fontFamily)
@@ -1394,7 +1168,7 @@ float Controller::GetInputFontPointSize() const
 
 void Controller::SetInputLineSpacing(float lineSpacing)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.lineSpacing          = lineSpacing;
     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
@@ -1403,17 +1177,12 @@ void Controller::SetInputLineSpacing(float lineSpacing)
 
 float Controller::GetInputLineSpacing() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.lineSpacing;
-  }
-
-  return 0.f;
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.lineSpacing : 0.0f;
 }
 
 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
   }
@@ -1421,17 +1190,12 @@ void Controller::SetInputShadowProperties(const std::string& shadowProperties)
 
 const std::string& Controller::GetInputShadowProperties() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.shadowProperties;
-  }
-
-  return EMPTY_STRING;
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.shadowProperties : EMPTY_STRING;
 }
 
 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
   }
@@ -1439,17 +1203,12 @@ void Controller::SetInputUnderlineProperties(const std::string& underlinePropert
 
 const std::string& Controller::GetInputUnderlineProperties() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.underlineProperties;
-  }
-
-  return EMPTY_STRING;
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.underlineProperties : EMPTY_STRING;
 }
 
 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
   }
@@ -1457,17 +1216,12 @@ void Controller::SetInputEmbossProperties(const std::string& embossProperties)
 
 const std::string& Controller::GetInputEmbossProperties() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.embossProperties;
-  }
-
-  return GetDefaultEmbossProperties();
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.embossProperties : GetDefaultEmbossProperties();
 }
 
 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
   }
@@ -1475,17 +1229,12 @@ void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
 
 const std::string& Controller::GetInputOutlineProperties() const
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mInputStyle.outlineProperties;
-  }
-
-  return GetDefaultOutlineProperties();
+  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.outlineProperties : GetDefaultOutlineProperties();
 }
 
 void Controller::SetInputModePassword(bool passwordInput)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mPasswordInput = passwordInput;
   }
@@ -1493,16 +1242,12 @@ void Controller::SetInputModePassword(bool passwordInput)
 
 bool Controller::IsInputModePassword()
 {
-  if(NULL != mImpl->mEventData)
-  {
-    return mImpl->mEventData->mPasswordInput;
-  }
-  return false;
+  return mImpl->mEventData && mImpl->mEventData->mPasswordInput;
 }
 
 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mDoubleTapAction = action;
   }
@@ -1510,19 +1255,12 @@ void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
 
 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
 {
-  NoTextTap::Action action = NoTextTap::NO_ACTION;
-
-  if(NULL != mImpl->mEventData)
-  {
-    action = mImpl->mEventData->mDoubleTapAction;
-  }
-
-  return action;
+  return mImpl->mEventData ? mImpl->mEventData->mDoubleTapAction : NoTextTap::NO_ACTION;
 }
 
 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     mImpl->mEventData->mLongPressAction = action;
   }
@@ -1530,14 +1268,7 @@ void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
 
 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
 {
-  NoTextTap::Action action = NoTextTap::NO_ACTION;
-
-  if(NULL != mImpl->mEventData)
-  {
-    action = mImpl->mEventData->mLongPressAction;
-  }
-
-  return action;
+  return mImpl->mEventData ? mImpl->mEventData->mLongPressAction : NoTextTap::NO_ACTION;
 }
 
 bool Controller::IsUnderlineSetByString()
@@ -1580,8 +1311,6 @@ void Controller::FontStyleSetByString(bool setByString)
   mImpl->mFontStyleSetByString = setByString;
 }
 
-// public : Queries & retrieves.
-
 Layout::Engine& Controller::GetLayoutEngine()
 {
   return mImpl->mLayoutEngine;
@@ -1615,8 +1344,7 @@ float Controller::GetHeightForWidth(float width)
 int Controller::GetLineCount(float width)
 {
   GetHeightForWidth(width);
-  int numberofLines = mImpl->mModel->GetNumberOfLines();
-  return numberofLines;
+  return mImpl->mModel->GetNumberOfLines();
 }
 
 const ModelInterface* const Controller::GetTextModel() const
@@ -1650,16 +1378,13 @@ bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight,
 
 void Controller::SetHiddenInputOption(const Property::Map& options)
 {
-  if(NULL == mImpl->mHiddenInput)
-  {
-    mImpl->mHiddenInput = new HiddenText(this);
-  }
+  EnsureCreated<HiddenText, Controller*>(mImpl->mHiddenInput, this);
   mImpl->mHiddenInput->SetProperties(options);
 }
 
 void Controller::GetHiddenInputOption(Property::Map& options)
 {
-  if(NULL != mImpl->mHiddenInput)
+  if(mImpl->mHiddenInput)
   {
     mImpl->mHiddenInput->GetProperties(options);
   }
@@ -1667,16 +1392,13 @@ void Controller::GetHiddenInputOption(Property::Map& options)
 
 void Controller::SetInputFilterOption(const Property::Map& options)
 {
-  if(!mImpl->mInputFilter)
-  {
-    mImpl->mInputFilter = std::unique_ptr<InputFilter>(new InputFilter());
-  }
+  EnsureCreated(mImpl->mInputFilter);
   mImpl->mInputFilter->SetProperties(options);
 }
 
 void Controller::GetInputFilterOption(Property::Map& options)
 {
-  if(NULL != mImpl->mInputFilter)
+  if(mImpl->mInputFilter)
   {
     mImpl->mInputFilter->GetProperties(options);
   }
@@ -1757,8 +1479,6 @@ void Controller::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type
   mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
 }
 
-// public : Relayout.
-
 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
 {
   return Relayouter::Relayout(*this, size, layoutDirection);
@@ -1769,8 +1489,6 @@ void Controller::RequestRelayout()
   mImpl->RequestRelayout();
 }
 
-// public : Input style change signals.
-
 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
 {
   return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
@@ -1778,31 +1496,20 @@ bool Controller::IsInputStyleChangedSignalsQueueEmpty()
 
 void Controller::ProcessInputStyleChangedSignals()
 {
-  if(NULL == mImpl->mEventData)
-  {
-    // Nothing to do.
-    return;
-  }
-
-  for(Vector<InputStyle::Mask>::ConstIterator it    = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
-                                              endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
-      it != endIt;
-      ++it)
+  if(mImpl->mEventData)
   {
-    const InputStyle::Mask mask = *it;
-
-    if(NULL != mImpl->mEditableControlInterface)
+    if(mImpl->mEditableControlInterface)
     {
-      // Emit the input style changed signal.
-      mImpl->mEditableControlInterface->InputStyleChanged(mask);
+      // Emit the input style changed signal for each mask
+      std::for_each(mImpl->mEventData->mInputStyleChangedQueue.begin(),
+                    mImpl->mEventData->mInputStyleChangedQueue.end(),
+                    [&](const auto mask) { mImpl->mEditableControlInterface->InputStyleChanged(mask); } );
     }
-  }
 
-  mImpl->mEventData->mInputStyleChangedQueue.Clear();
+    mImpl->mEventData->mInputStyleChangedQueue.Clear();
+  }
 }
 
-// public : Text-input Event Queuing.
-
 void Controller::KeyboardFocusGainEvent()
 {
   EventHandler::KeyboardFocusGainEvent(*this);
@@ -1933,7 +1640,7 @@ string Controller::CutText()
 
   if(!IsEditable())
   {
-    return "";
+    return EMPTY_STRING;
   }
 
   mImpl->SendSelectionToClipboard(true); // Synchronous call to modify text
@@ -1976,8 +1683,6 @@ void Controller::PasteClipboardItemEvent()
   EventHandler::PasteClipboardItemEvent(*this);
 }
 
-// protected : Inherit from Text::Decorator::ControllerInterface.
-
 void Controller::GetTargetSize(Vector2& targetSize)
 {
   targetSize = mImpl->mModel->mVisualModel->mControlSize;
@@ -1985,7 +1690,7 @@ void Controller::GetTargetSize(Vector2& targetSize)
 
 void Controller::AddDecoration(Actor& actor, bool needsClipping)
 {
-  if(NULL != mImpl->mEditableControlInterface)
+  if(mImpl->mEditableControlInterface)
   {
     mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
   }
@@ -2037,22 +1742,14 @@ void Controller::ScrollBy(Vector2 scroll)
 
 float Controller::GetHorizontalScrollPosition()
 {
-  if(mImpl->mEventData)
-  {
-    //scroll values are negative internally so we convert them to positive numbers
-    return -mImpl->mModel->mScrollPosition.x;
-  }
-  return 0;
+  // Scroll values are negative internally so we convert them to positive numbers
+  return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.x : 0.0f;
 }
 
 float Controller::GetVerticalScrollPosition()
 {
-  if(mImpl->mEventData)
-  {
-    //scroll values are negative internally so we convert them to positive numbers
-    return -mImpl->mModel->mScrollPosition.y;
-  }
-  return 0;
+  // Scroll values are negative internally so we convert them to positive numbers
+  return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.y : 0.0f;
 }
 
 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
@@ -2060,8 +1757,6 @@ void Controller::DecorationEvent(HandleType handleType, HandleState state, float
   EventHandler::DecorationEvent(*this, handleType, state, x, y);
 }
 
-// protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
-
 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
 {
   EventHandler::TextPopupButtonTouched(*this, button);
@@ -2076,8 +1771,6 @@ void Controller::DisplayTimeExpired()
   mImpl->RequestRelayout();
 }
 
-// private : Update.
-
 void Controller::InsertText(const std::string& text, Controller::InsertType type)
 {
   TextUpdater::InsertText(*this, text, type);
@@ -2088,9 +1781,7 @@ void Controller::PasteText(const std::string& stringToPaste)
   TextUpdater::PasteText(*this, stringToPaste);
 }
 
-bool Controller::RemoveText(int                  cursorOffset,
-                            int                  numberOfCharacters,
-                            UpdateInputStyleType type)
+bool Controller::RemoveText(int cursorOffset, int numberOfCharacters, UpdateInputStyleType type)
 {
   return TextUpdater::RemoveText(*this, cursorOffset, numberOfCharacters, type);
 }
@@ -2100,24 +1791,17 @@ bool Controller::RemoveSelectedText()
   return TextUpdater::RemoveSelectedText(*this);
 }
 
-void Controller::InsertTextAnchor(int            numberOfCharacters,
-                                  CharacterIndex previousCursorIndex)
+void Controller::InsertTextAnchor(int numberOfCharacters, CharacterIndex previousCursorIndex)
 {
   TextUpdater::InsertTextAnchor(*this, numberOfCharacters, previousCursorIndex);
 }
 
-void Controller::RemoveTextAnchor(int            cursorOffset,
-                                  int            numberOfCharacters,
-                                  CharacterIndex previousCursorIndex)
+void Controller::RemoveTextAnchor(int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
 {
   TextUpdater::RemoveTextAnchor(*this, cursorOffset, numberOfCharacters, previousCursorIndex);
 }
 
-// private : Relayout.
-
-bool Controller::DoRelayout(const Size&    size,
-                            OperationsMask operationsRequired,
-                            Size&          layoutSize)
+bool Controller::DoRelayout(const Size& size, OperationsMask operationsRequired, Size& layoutSize)
 {
   return Relayouter::DoRelayout(*this, size, operationsRequired, layoutSize);
 }
@@ -2127,8 +1811,6 @@ void Controller::CalculateVerticalOffset(const Size& controlSize)
   Relayouter::CalculateVerticalOffset(*this, controlSize);
 }
 
-// private : Events.
-
 void Controller::ProcessModifyEvents()
 {
   EventHandler::ProcessModifyEvents(*this);
@@ -2224,7 +1906,7 @@ CharacterIndex Controller::GetCursorPosition()
 
 void Controller::ResetScrollPosition()
 {
-  if(NULL != mImpl->mEventData)
+  if(mImpl->mEventData)
   {
     // Reset the scroll position.
     mImpl->mModel->mScrollPosition                = Vector2::ZERO;
@@ -2252,18 +1934,6 @@ Actor Controller::CreateBackgroundActor()
   return mImpl->CreateBackgroundActor();
 }
 
-// private : Private contructors & copy operator.
-
-Controller::Controller()
-: Controller(nullptr, nullptr, nullptr, nullptr)
-{
-}
-
-Controller::Controller(ControlInterface* controlInterface)
-: Controller(controlInterface, nullptr, nullptr, nullptr)
-{
-}
-
 Controller::Controller(ControlInterface*           controlInterface,
                        EditableControlInterface*   editableControlInterface,
                        SelectableControlInterface* selectableControlInterface,
@@ -2272,17 +1942,9 @@ Controller::Controller(ControlInterface*           controlInterface,
 {
 }
 
-// The copy constructor and operator are left unimplemented.
-
-// protected : Destructor.
-
 Controller::~Controller()
 {
   delete mImpl;
 }
 
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+} // namespace Dali::Toolkit::Text
index 9302cf5..3240384 100644 (file)
 #include <dali-toolkit/internal/text/text-selectable-control-interface.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
-namespace Dali
-{
-namespace Toolkit
-{
-namespace Text
+namespace Dali::Toolkit::Text
 {
 class Controller;
 class ControlInterface;
@@ -170,7 +166,10 @@ public: // Constructor.
    *
    * @return A pointer to a new Controller.
    */
-  static ControllerPtr New();
+  static ControllerPtr New()
+  {
+    return ControllerPtr(new Controller());
+  }
 
   /**
    * @brief Create a new instance of a Controller.
@@ -179,7 +178,10 @@ public: // Constructor.
    *
    * @return A pointer to a new Controller.
    */
-  static ControllerPtr New(ControlInterface* controlInterface);
+  static ControllerPtr New(ControlInterface* controlInterface)
+  {
+    return ControllerPtr(new Controller(controlInterface));
+  }
 
   /**
    * @brief Create a new instance of a Controller.
@@ -194,7 +196,13 @@ public: // Constructor.
   static ControllerPtr New(ControlInterface*           controlInterface,
                            EditableControlInterface*   editableControlInterface,
                            SelectableControlInterface* selectableControlInterface,
-                           AnchorControlInterface*     anchorControlInterface);
+                           AnchorControlInterface*     anchorControlInterface)
+  {
+    return ControllerPtr(new Controller(controlInterface,
+                                        editableControlInterface,
+                                        selectableControlInterface,
+                                        anchorControlInterface));
+  }
 
 public: // Configure the text controller.
   /**
@@ -1897,12 +1905,18 @@ private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.
    */
-  Controller();
+  Controller()
+  : Controller(nullptr, nullptr, nullptr, nullptr)
+  {
+  }
 
   /**
    * @brief Private constructor.
    */
-  Controller(ControlInterface* controlInterface);
+  Controller(ControlInterface* controlInterface)
+  : Controller(controlInterface, nullptr, nullptr, nullptr)
+  {
+  }
 
   /**
    * @brief Private constructor.
@@ -1912,11 +1926,8 @@ private: // Private contructors & copy operator.
              SelectableControlInterface* selectableControlInterface,
              AnchorControlInterface*     anchorControlInterface);
 
-  // Undefined
-  Controller(const Controller& handle);
-
-  // Undefined
-  Controller& operator=(const Controller& handle);
+  Controller(const Controller& handle) = delete;
+  Controller& operator=(const Controller& handle) = delete;
 
 protected: // Destructor.
   /**
@@ -1937,10 +1948,6 @@ private:
   Impl* mImpl;
 };
 
-} // namespace Text
-
-} // namespace Toolkit
-
-} // namespace Dali
+} // namespace Dali::Toolkit::Text
 
 #endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
index f8aed47..5ee926e 100644 (file)
@@ -208,22 +208,18 @@ void TransitionBase::SetAnimation()
     return;
   }
 
-  // If this transition is not a transition from a Control to another Control
-  // and a transition effect to appear with delay,
-  // the mTarget should not be shown until delay seconds.
-  if(!IsPairTransition() && mIsAppearingTransition && mAnimation && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
-  {
-    Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
-    initialKeyframes.Add(0.0f, OPACITY_TRANSPARENT);
-    initialKeyframes.Add(1.0f, OPACITY_TRANSPARENT);
-    mAnimation.AnimateBetween(Property(mTarget, Dali::Actor::Property::OPACITY), initialKeyframes, TimePeriod(mTimePeriod.delaySeconds));
-  }
-
   for(uint32_t i = 0; i < mStartPropertyMap.Count(); ++i)
   {
     Property::Value* finishValue = mFinishPropertyMap.Find(mStartPropertyMap.GetKeyAt(i).indexKey);
     if(finishValue)
     {
+      // If this transition is appearing transition, this property keeps start value during delay.
+      // If multiple transitions are applied to this Control and others run before this transition,
+      // this property should keep start value until this transition starts.
+      if(!IsPairTransition() && IsAppearingTransition() && mTimePeriod.delaySeconds > Dali::Math::MACHINE_EPSILON_10)
+      {
+        mTarget.SetProperty(mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i));
+      }
       AnimateBetween(mTarget, mStartPropertyMap.GetKeyAt(i).indexKey, mStartPropertyMap.GetValue(i), *finishValue);
     }
   }
index 409eb60..b194e52 100644 (file)
@@ -101,6 +101,30 @@ public:
     mIsAppearingTransition = appearingTransition;
   }
 
+  /**
+   * @brief Returns whether this transition is appearing transition or not
+   */
+  bool IsAppearingTransition() const
+  {
+    return mIsAppearingTransition;
+  }
+
+  /**
+   * @brief Returns whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
+   */
+  bool IsPairTransition() const
+  {
+    return mIsPairTransition;
+  }
+
+  /**
+   * @brief Returns target which will be transition.
+   */
+  const Dali::Toolkit::Control GetTarget() const
+  {
+    return mTarget;
+  }
+
 protected:
 
   /**
@@ -159,14 +183,6 @@ protected:
   }
 
   /**
-   * @brief Returns whether this transition is appearing transition or not
-   */
-  bool IsAppearingTransition() const
-  {
-    return mIsAppearingTransition;
-  }
-
-  /**
    * @brief Set whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
    * @param[in] pairTransition True if this transition is appearing transition.
    */
@@ -175,14 +191,6 @@ protected:
     mIsPairTransition = pairTransition;
   }
 
-  /**
-   * @brief Returns whether this transition is a transition from a Control to another Control or effect to appearing or disappearing.
-   */
-  bool IsPairTransition() const
-  {
-    return mIsPairTransition;
-  }
-
 protected:
   /**
    * Construct a new TransitionBase.
index 2cbd14d..78ba8db 100644 (file)
@@ -27,6 +27,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
 namespace Dali
 {
@@ -37,10 +38,9 @@ namespace Internal
 namespace
 {
 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION(Dali::AlphaFunction::DEFAULT);
-
 } // anonymous namespace
 
-TransitionPtr Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+TransitionPtr Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, bool useDestinationTarget, TimePeriod timePeriod)
 {
   float delaySeconds = timePeriod.delaySeconds;
   if(delaySeconds < 0.0f)
@@ -56,7 +56,7 @@ TransitionPtr Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Cont
     durationSeconds = 0.0f;
   }
 
-  TransitionPtr transition = new Transition(source, destination, TimePeriod(delaySeconds, durationSeconds));
+  TransitionPtr transition = new Transition(source, destination, useDestinationTarget, TimePeriod(delaySeconds, durationSeconds));
 
   // Second-phase construction
   transition->Initialize();
@@ -64,12 +64,14 @@ TransitionPtr Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Cont
   return transition;
 }
 
-Transition::Transition(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+Transition::Transition(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, bool useDestinationTarget, TimePeriod timePeriod)
 : TransitionBase(),
+  mUseDestinationTarget(useDestinationTarget),
+  mOriginalSize(),
   mSourceControl(source),
   mDestinationControl(destination)
 {
-  SetTarget(destination);
+  SetTarget(mUseDestinationTarget ? destination : source);
   SetTimePeriod(timePeriod);
   SetPairTransition(true);
 }
@@ -90,16 +92,15 @@ void Transition::OnPlay()
   }
 
   //Make startPropertyMap and finishPropertyMap to use for property animation.
-  Matrix     sourceWorldTransform = sourceControl[Dali::Actor::Property::WORLD_MATRIX];
+  Matrix     sourceWorldTransform = GetWorldTransform(sourceControl);
   Vector3    sourcePosition, sourceScale;
   Quaternion sourceOrientation;
   sourceWorldTransform.GetTransformComponents(sourcePosition, sourceOrientation, sourceScale);
 
-  Vector3    destinationPosition    = destinationControl[Dali::Actor::Property::POSITION];
-  Vector3    destinationScale       = destinationControl[Dali::Actor::Property::SCALE];
-  Quaternion destinationOrientation = destinationControl[Dali::Actor::Property::ORIENTATION];
-  Vector4    targetColor            = destinationControl[Dali::Actor::Property::COLOR];
-  Vector3    targetSize             = destinationControl[Dali::Actor::Property::SIZE];
+  Matrix     destinationWorldTransform = GetWorldTransform(destinationControl);
+  Vector3    destinationPosition, destinationScale;
+  Quaternion destinationOrientation;
+  destinationWorldTransform.GetTransformComponents(destinationPosition, destinationOrientation, destinationScale);
 
   Property::Map startPropertyMap;
   Property::Map finishPropertyMap;
@@ -114,29 +115,36 @@ void Transition::OnPlay()
   startPropertyMap.Insert(Dali::Actor::Property::SCALE, sourceScale);
   finishPropertyMap.Insert(Dali::Actor::Property::SCALE, destinationScale);
 
-  Vector4 sourceColor = sourceControl.GetCurrentProperty<Vector4>(Dali::Actor::Property::WORLD_COLOR);
+  Vector4 sourceColor      = GetWorldColor(sourceControl);
+  Vector4 destinationColor = GetWorldColor(destinationControl);
   startPropertyMap.Insert(Dali::Actor::Property::COLOR, sourceColor);
-  finishPropertyMap.Insert(Dali::Actor::Property::COLOR, targetColor);
+  finishPropertyMap.Insert(Dali::Actor::Property::COLOR, destinationColor);
 
   // Set animation for other properties if source and destination is different.
-  Vector3 sourceSize = sourceControl.GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE);
-  if(sourceSize != targetSize)
+  Vector3 sourceSize      = sourceControl[Dali::Actor::Property::SIZE];
+  Vector3 destinationSize = destinationControl[Dali::Actor::Property::SIZE];
+  if(sourceSize != destinationSize)
   {
     startPropertyMap.Insert(Dali::Actor::Property::SIZE, sourceSize);
-    finishPropertyMap.Insert(Dali::Actor::Property::SIZE, targetSize);
+    finishPropertyMap.Insert(Dali::Actor::Property::SIZE, destinationSize);
+    if(!mUseDestinationTarget)
+    {
+      mOriginalSize = GetTargetControl().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+    }
   }
 
   SetStartPropertyMap(startPropertyMap);
   SetFinishPropertyMap(finishPropertyMap);
 
   // source View becomes transparent during transition.
+  Dali::Toolkit::Control waitingControl = GetWaitingControl();
   if(IsTransitionWithChild())
   {
-    sourceControl[Dali::Actor::Property::VISIBLE] = false;
+    waitingControl[Dali::Actor::Property::VISIBLE] = false;
   }
   else
   {
-    GetImplementation(sourceControl).SetTransparent(true);
+    GetImplementation(waitingControl).SetTransparent(true);
   }
 
   Dali::Animation animation = GetAnimation();
@@ -145,27 +153,82 @@ void Transition::OnPlay()
     DALI_LOG_ERROR("animation is still not initialized\n");
     return;
   }
-  Dali::Toolkit::DevelControl::CreateTransitions(destinationControl, animation, sourceControl, GetAlphaFunction(), GetTimePeriod());
+
+  mOriginalVisualProperties.clear();
+  std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>> destinationVisualProperties;
+  Dali::Toolkit::Control                                             targetControl   = GetTargetControl();
+  Internal::Control&                                                 internalControl = Toolkit::Internal::GetImplementation(targetControl);
+  Internal::Control::Impl&                                           controlDataImpl = Toolkit::Internal::Control::Impl::Get(internalControl);
+  controlDataImpl.CreateTransitions(mOriginalVisualProperties, destinationVisualProperties, sourceControl, destinationControl);
+
+  for(uint32_t index = 0; index < mOriginalVisualProperties.size(); ++index)
+  {
+    Dali::Property::Map source      = mOriginalVisualProperties[index].second;
+    Dali::Property::Map destination = destinationVisualProperties[index].second;
+    for(size_t i = 0; i < source.Count(); ++i)
+    {
+      Dali::Property property = DevelControl::GetVisualProperty(targetControl, mOriginalVisualProperties[index].first, source.GetKeyAt(i));
+      if(GetTimePeriod().delaySeconds > 0.0f)
+      {
+        Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+        initialKeyframes.Add(0.0f, source.GetValue(i));
+        animation.AnimateBetween(property, initialKeyframes, TimePeriod(GetTimePeriod().delaySeconds));
+      }
+      Dali::KeyFrames keyframes = Dali::KeyFrames::New();
+      keyframes.Add(0.0f, source.GetValue(i));
+      keyframes.Add(1.0f, destination.GetValue(i));
+      animation.AnimateBetween(property, keyframes, GetAlphaFunction(), GetTimePeriod());
+    }
+  }
 }
 
 void Transition::OnFinished()
 {
-  Dali::Toolkit::Control sourceControl = mSourceControl.GetHandle();
-  if(!sourceControl)
+  Dali::Toolkit::Control waitingControl = GetWaitingControl();
+  if(!waitingControl)
   {
     return;
   }
 
+  if(!mUseDestinationTarget)
+  {
+    Dali::Toolkit::Control target         = GetTargetControl();
+    Dali::Animation        resetAnimation = Dali::Animation::New(0.0f);
+    if(mOriginalSize != target.GetProperty<Vector3>(Dali::Actor::Property::SIZE))
+    {
+      // Use Animation not to notify size change and not to change width and height resize policy.
+      resetAnimation.AnimateTo(Dali::Property(target, Dali::Actor::Property::SIZE), mOriginalSize);
+    }
+    resetAnimation.Play();
+
+    Dali::Toolkit::Control   targetControl   = GetTargetControl();
+    Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(targetControl);
+    Internal::Control::Impl& controlDataImpl = Toolkit::Internal::Control::Impl::Get(internalControl);
+    controlDataImpl.UpdateVisualProperties(mOriginalVisualProperties);
+  }
+
   if(IsTransitionWithChild())
   {
-    sourceControl[Dali::Actor::Property::VISIBLE] = true;
+    waitingControl[Dali::Actor::Property::VISIBLE] = true;
   }
   else
   {
-    GetImplementation(sourceControl).SetTransparent(false);
+    GetImplementation(waitingControl).SetTransparent(false);
   }
 }
 
+Dali::Toolkit::Control Transition::GetTargetControl()
+{
+  Dali::Toolkit::Control target = mUseDestinationTarget ? mDestinationControl.GetHandle() : mSourceControl.GetHandle();
+  return target;
+}
+
+Dali::Toolkit::Control Transition::GetWaitingControl()
+{
+  Dali::Toolkit::Control waitingControl = mUseDestinationTarget ? mSourceControl.GetHandle() : mDestinationControl.GetHandle();
+  return waitingControl;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 6aa1374..7230e2b 100644 (file)
@@ -41,10 +41,11 @@ public:
    * @brief Create a new Transition object.
    * @param[in] source A source control of this transition.
    * @param[in] destination A destination control of this transition.
+   * @param[in] useDestinationTarget True if this transition uses destination control as target.
    * @param[in] timePeriod The timePeriod of the animation.
    * @return A smart-pointer to the newly allocated Transition.
    */
-  static TransitionPtr New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod);
+  static TransitionPtr New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, bool useDestinationTarget, TimePeriod timePeriod);
 
 protected:
   /**
@@ -63,6 +64,7 @@ protected:
    */
   Transition(Dali::Toolkit::Control source,
              Dali::Toolkit::Control destination,
+             bool                   useDestinationTarget,
              TimePeriod             timePeriod);
 
   /**
@@ -78,8 +80,15 @@ private:
   Transition& operator=(const Transition& rhs);
 
 private:
-  WeakHandle<Dali::Toolkit::Control> mSourceControl;
-  WeakHandle<Dali::Toolkit::Control> mDestinationControl;
+  Dali::Toolkit::Control GetTargetControl();
+  Dali::Toolkit::Control GetWaitingControl();
+
+private:
+  bool                                                               mUseDestinationTarget;
+  Vector3                                                            mOriginalSize;
+  std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>> mOriginalVisualProperties;
+  WeakHandle<Dali::Toolkit::Control>                                 mSourceControl;
+  WeakHandle<Dali::Toolkit::Control>                                 mDestinationControl;
 };
 
 } // namespace Internal
index fd019b6..d1b16af 100644 (file)
@@ -37,6 +37,13 @@ namespace
 // Signals
 static constexpr std::string_view SIGNAL_FINISHED = "finished";
 
+static constexpr float OPACITY_TRANSPARENT = 0.0f;
+
+float CustomAlphaFunction(float progress)
+{
+  return (progress >= 1.0f) ? 1.0f : 0.0f;
+}
+
 BaseHandle Create()
 {
   return Dali::Toolkit::TransitionSet::New();
@@ -117,9 +124,46 @@ void TransitionSet::TransitionPreProcess()
 
 void TransitionSet::TransitionStart()
 {
+  std::vector<std::pair<Dali::Actor, float>> minimumDelays;
   for(auto&& transition : mTransitions)
   {
     transition->Play();
+
+    // If target Control has appearing transition, the target will not be rendered during delay.
+    // And if the Control has multiple transitions, the target will not be rendered during minimum delay of the transitions.
+    // Here we can find minimum delay of each target.
+    if(!transition->IsPairTransition() && transition->IsAppearingTransition())
+    {
+      bool found = false;
+      for(uint32_t index = 0; index < minimumDelays.size(); ++index)
+      {
+        if(minimumDelays[index].first == transition->GetTarget())
+        {
+          minimumDelays[index].second = std::min(minimumDelays[index].second, transition->GetTimePeriod().delaySeconds);
+          found = true;
+          break;
+        }
+      }
+      if(!found)
+      {
+        minimumDelays.push_back(std::pair<Dali::Actor, float>(transition->GetTarget(), transition->GetTimePeriod().delaySeconds));
+      }
+    }
+  }
+
+  // If the target has delay that is larger than 0, hide the target during minimum delay.
+  // The custom alpha function make the target hide just during delay.
+  for(auto&& delay : minimumDelays)
+  {
+    if(delay.second > Dali::Math::MACHINE_EPSILON_10)
+    {
+      Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+      initialKeyframes.Add(0.0f, OPACITY_TRANSPARENT);
+      initialKeyframes.Add(1.0f, delay.first.GetProperty<float>(Dali::Actor::Property::OPACITY));
+
+      AlphaFunction alpha(&CustomAlphaFunction);
+      mAnimation.AnimateBetween(Property(delay.first, Dali::Actor::Property::OPACITY), initialKeyframes, alpha, TimePeriod(delay.second));
+    }
   }
 
   mAnimation.FinishedSignal().Connect(this, &TransitionSet::TransitionFinished);
index 9693cc8..d8d61d3 100644 (file)
@@ -187,9 +187,9 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
   mUrlIndex(0),
   mFrameCount(0),
   mImageSize(),
+  mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
   mWrapModeU(WrapMode::DEFAULT),
   mWrapModeV(WrapMode::DEFAULT),
-  mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mStartFirstFrame(false),
   mIsJumpTo(false)
index 347e9d3..1d21356 100644 (file)
@@ -275,9 +275,10 @@ private:
   uint32_t        mFrameCount; // Number of frames
   ImageDimensions mImageSize;
 
+  DevelAnimatedImageVisual::Action::Type mActionStatus;
+
   Dali::WrapMode::Type                   mWrapModeU : 3;
   Dali::WrapMode::Type                   mWrapModeV : 3;
-  DevelAnimatedImageVisual::Action::Type mActionStatus : 3;
   DevelImageVisual::StopBehavior::Type   mStopBehavior : 2;
   bool                                   mStartFirstFrame : 1;
   bool                                   mIsJumpTo : 1;
index 89d02e8..26495bf 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
@@ -445,15 +446,6 @@ void AnimatedVectorImageVisual::OnDoAction(const Property::Index actionId, const
       }
       break;
     }
-    case DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY:
-    {
-      const Property::Map* map = attributes.GetMap();
-      if(map)
-      {
-        DoSetProperties(*map);
-      }
-      break;
-    }
   }
 
   TriggerVectorRasterization();
index 76328f4..a1c79e9 100644 (file)
@@ -22,7 +22,6 @@
 #include <dali/integration-api/debug.h>
 
 //INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/visuals/arc-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
@@ -188,23 +187,6 @@ void ArcVisual::OnSetTransform()
   }
 }
 
-void ArcVisual::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
-{
-  // Check if action is valid for this visual type and perform action if possible
-  switch(actionId)
-  {
-    case DevelArcVisual::Action::UPDATE_PROPERTY:
-    {
-      const Property::Map* map = attributes.GetMap();
-      if(map)
-      {
-        DoSetProperties(*map);
-      }
-      break;
-    }
-  }
-}
-
 void ArcVisual::OnInitialize()
 {
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
index 4746351..011b946 100644 (file)
@@ -107,11 +107,6 @@ protected:
    */
   void OnSetTransform() override;
 
-  /**
-   * @copydoc Visual::Base::OnDoAction
-   */
-  void OnDoAction(const Property::Index actionId, const Property::Value& attributes) override;
-
 private:
   // Undefined
   ArcVisual(const ArcVisual& arcVisual) = delete;
index 593eeb6..73b0931 100644 (file)
@@ -23,7 +23,6 @@
 #include <dali/integration-api/debug.h>
 
 //INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/visuals/color-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
@@ -161,23 +160,6 @@ void ColorVisual::OnSetTransform()
   }
 }
 
-void ColorVisual::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
-{
-  // Check if action is valid for this visual type and perform action if possible
-  switch(actionId)
-  {
-    case DevelColorVisual::Action::UPDATE_PROPERTY:
-    {
-      const Property::Map* map = attributes.GetMap();
-      if(map)
-      {
-        DoSetProperties(*map);
-      }
-      break;
-    }
-  }
-}
-
 void ColorVisual::UpdateShader()
 {
   if(mImpl->mRenderer)
index 6ced771..5edf2ba 100644 (file)
@@ -104,11 +104,6 @@ protected:
   void OnSetTransform() override;
 
   /**
-   * @copydoc Visual::Base::OnDoAction
-   */
-  void OnDoAction(const Property::Index actionId, const Property::Value& attributes) override;
-
-  /**
    * @copydoc Visual::Base::UpdateShader
    */
   void UpdateShader() override;
index 19ecb5c..a4903c5 100644 (file)
@@ -23,7 +23,6 @@
 #include <dali/devel-api/images/pixel-data-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
-#include <dali/public-api/animation/constraints.h>
 #include <string.h>
 
 // INTERNAL HEADER
@@ -240,6 +239,7 @@ TextVisual::TextVisual(VisualFactoryCache& factoryCache)
   mController(Text::Controller::New()),
   mTypesetter(Text::Typesetter::New(mController->GetTextModel())),
   mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX),
+  mTextColorAnimatableIndex(Property::INVALID_INDEX),
   mRendererUpdateNeeded(false)
 {
 }
@@ -291,23 +291,36 @@ void TextVisual::DoSetOnScene(Actor& actor)
   // Enable the pre-multiplied alpha to improve the text quality
   EnablePreMultipliedAlpha(true);
 
-  const Vector4&        defaultColor         = mController->GetTextModel()->GetDefaultColor();
-  Dali::Property::Index shaderTextColorIndex = mImpl->mRenderer.RegisterProperty("uTextColorAnimatable", defaultColor);
+  const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
+  if(mTextColorAnimatableIndex == Property::INVALID_INDEX)
+  {
+    mTextColorAnimatableIndex = mImpl->mRenderer.RegisterProperty("uTextColorAnimatable", defaultColor);
+  }
+  else
+  {
+    mImpl->mRenderer.SetProperty(mTextColorAnimatableIndex, defaultColor);
+  }
 
   if(mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX)
   {
     // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
-    if(shaderTextColorIndex != Property::INVALID_INDEX)
+    if(mTextColorAnimatableIndex != Property::INVALID_INDEX)
     {
-      Constraint colorConstraint = Constraint::New<Vector4>(mImpl->mRenderer, shaderTextColorIndex, TextColorConstraint);
-      colorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
-      colorConstraint.Apply();
-
-      // Make zero if the alpha value of text color is zero to skip rendering text
-      Constraint opacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
-      opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
-      opacityConstraint.Apply();
+      if(!mColorConstraint)
+      {
+        mColorConstraint = Constraint::New<Vector4>(mImpl->mRenderer, mTextColorAnimatableIndex, TextColorConstraint);
+        mColorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+      }
+      mColorConstraint.Apply();
     }
+
+    // Make zero if the alpha value of text color is zero to skip rendering text
+    if(!mOpacityConstraint)
+    {
+      mOpacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
+      mOpacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+    }
+    mOpacityConstraint.Apply();
   }
 
   // Renderer needs textures and to be added to control
@@ -335,6 +348,15 @@ void TextVisual::RemoveRenderer(Actor& actor)
 
 void TextVisual::DoSetOffScene(Actor& actor)
 {
+  if(mColorConstraint)
+  {
+    mColorConstraint.Remove();
+  }
+  if(mOpacityConstraint)
+  {
+    mOpacityConstraint.Remove();
+  }
+
   RemoveRenderer(actor);
 
   // Resets the control handle.
index 7ae5e4e..f9d6c79 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
 #include <dali/public-api/object/base-object.h>
 #include <dali/public-api/object/weak-handle.h>
 
@@ -332,7 +333,10 @@ private:
   Text::ControllerPtr mController;                       ///< The text's controller.
   Text::TypesetterPtr mTypesetter;                       ///< The text's typesetter.
   WeakHandle<Actor>   mControl;                          ///< The control where the renderer is added.
+  Constraint          mColorConstraint{};                ///< Color constraint
+  Constraint          mOpacityConstraint{};              ///< Opacity constraint
   Property::Index     mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control.
+  Property::Index     mTextColorAnimatableIndex;         ///< The index of uTextColorAnimatable property.
   bool                mRendererUpdateNeeded : 1;         ///< The flag to indicate whether the renderer needs to be updated.
   RendererContainer   mRendererList;
 };
index 443c51c..f0a7af4 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 
 //INTERNAL HEARDER
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/internal/helpers/property-helper.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
@@ -294,6 +295,11 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
         {
           mImpl->mBorderlineWidth = width;
         }
+
+        if(mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+        {
+          mImpl->mRenderer.SetProperty(mImpl->mBorderlineWidthIndex, mImpl->mBorderlineWidth);
+        }
         break;
       }
       case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
@@ -303,6 +309,11 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
         {
           mImpl->mBorderlineColor = color;
         }
+
+        if(mImpl->mBorderlineColorIndex != Property::INVALID_INDEX)
+        {
+          mImpl->mRenderer.SetProperty(mImpl->mBorderlineColorIndex, mImpl->mBorderlineColor);
+        }
         break;
       }
       case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
@@ -312,6 +323,11 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
         {
           mImpl->mBorderlineOffset = offset;
         }
+
+        if(mImpl->mBorderlineOffsetIndex != Property::INVALID_INDEX)
+        {
+          mImpl->mRenderer.SetProperty(mImpl->mBorderlineOffsetIndex, mImpl->mBorderlineOffset);
+        }
         break;
       }
       case Toolkit::DevelVisual::Property::CORNER_RADIUS:
@@ -337,6 +353,11 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
             mImpl->mCornerRadius = Vector4(radius, radius, radius, radius);
           }
         }
+
+        if(mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
+        {
+          mImpl->mRenderer.SetProperty(mImpl->mCornerRadiusIndex, mImpl->mCornerRadius);
+        }
         break;
       }
       case Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY:
@@ -423,6 +444,20 @@ void Visual::Base::GetNaturalSize(Vector2& naturalSize)
 void Visual::Base::DoAction(const Property::Index actionId, const Property::Value attributes)
 {
   OnDoAction(actionId, attributes);
+
+  // Check if action is valid for this visual type and perform action if possible
+  switch(actionId)
+  {
+    case DevelVisual::Action::UPDATE_PROPERTY:
+    {
+      const Property::Map* map = attributes.GetMap();
+      if(map)
+      {
+        SetProperties(*map);
+      }
+      break;
+    }
+  }
 }
 
 void Visual::Base::SetDepthIndex(int index)
index 17db11b..64745d0 100644 (file)
@@ -37,7 +37,7 @@
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
-#include <dali-toolkit/devel-api/visuals/color-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
@@ -133,7 +133,7 @@ void Control::SetBackgroundColor(const Vector4& color)
   if(visual && visual.GetType() == Toolkit::Visual::COLOR)
   {
     // Update background color only
-    mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
+    mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, map);
     return;
   }
 
@@ -702,6 +702,102 @@ void Control::SignalDisconnected(SlotObserver* slotObserver, CallbackBase* callb
   mImpl->SignalDisconnected(slotObserver, callback);
 }
 
+void Control::MakeVisualTransition(Dali::Property::Map& sourcePropertyMap, Dali::Property::Map& destinationPropertyMap,
+                                   Dali::Toolkit::Control source, Dali::Toolkit::Control destination, Dali::Property::Index visualIndex)
+{
+  sourcePropertyMap.Clear();
+  destinationPropertyMap.Clear();
+
+  Toolkit::Visual::Base sourceVisual      = DevelControl::GetVisual(GetImplementation(source), visualIndex);
+  Toolkit::Visual::Base destinationVisual = DevelControl::GetVisual(GetImplementation(destination), visualIndex);
+
+  // If source or destination doesn't have the visual, do not create transition for the visual.
+  if(!sourceVisual || !destinationVisual)
+  {
+    return;
+  }
+
+  Property::Map sourceMap;
+  Property::Map destinationMap;
+  sourceVisual.CreatePropertyMap(sourceMap);
+  destinationVisual.CreatePropertyMap(destinationMap);
+
+  static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4
+  {
+    Property::Value* propertyValue = map.Find(index);
+    if(propertyValue)
+    {
+      return propertyValue->Get<Vector4>();
+    }
+    return defaultValue;
+  };
+
+  static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float
+  {
+    Property::Value* propertyValue = map.Find(index);
+    if(propertyValue)
+    {
+      return propertyValue->Get<float>();
+    }
+    return defaultValue;
+  };
+
+  Vector4 defaultMixColor(Color::TRANSPARENT);
+  Vector4 defaultCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
+  float   defaultBorderlineWidth(0.0f);
+  Vector4 defaultBorderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
+  float   defaultBorderlineOffset(0.0f);
+
+  Vector4 sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, defaultMixColor);
+  Vector4 sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, defaultCornerRadius);
+  float   sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, defaultBorderlineWidth);
+  Vector4 sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, defaultBorderlineColor);
+  float   sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, defaultBorderlineOffset);
+
+  Vector4 destinationMixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, defaultMixColor);
+  Vector4 destinationCornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, defaultCornerRadius);
+  float   destinationBorderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, defaultBorderlineWidth);
+  Vector4 destinationBorderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, defaultBorderlineColor);
+  float   destinationBorderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, defaultBorderlineOffset);
+
+  // If the value of the source Control and that of destination Control is different, the property should be transitioned.
+  if(Vector3(sourceMixColor) != Vector3(destinationMixColor))
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::Visual::Property::MIX_COLOR, Vector3(sourceMixColor));
+    destinationPropertyMap.Add(Dali::Toolkit::Visual::Property::MIX_COLOR, Vector3(destinationMixColor));
+  }
+
+  if(std::abs(sourceMixColor.a - destinationMixColor.a) > Math::MACHINE_EPSILON_1)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::Visual::Property::OPACITY, sourceMixColor.a);
+    destinationPropertyMap.Add(Dali::Toolkit::Visual::Property::OPACITY, destinationMixColor.a);
+  }
+
+  if(sourceCornerRadius != destinationCornerRadius)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS, sourceCornerRadius);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS, destinationCornerRadius);
+  }
+
+  if(sourceBorderlineWidth != destinationBorderlineWidth)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, sourceBorderlineWidth);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, destinationBorderlineWidth);
+  }
+
+  if(sourceBorderlineColor != destinationBorderlineColor)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR, sourceBorderlineColor);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR, destinationBorderlineColor);
+  }
+
+  if(sourceBorderlineOffset != destinationBorderlineOffset)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, sourceBorderlineOffset);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, destinationBorderlineOffset);
+  }
+}
+
 Control& GetImplementation(Dali::Toolkit::Control& handle)
 {
   CustomActorImpl& customInterface = handle.GetImplementation();
index 9a68ca1..48c6b9c 100644 (file)
@@ -45,6 +45,7 @@ class StyleManager;
 
 namespace Internal
 {
+
 /**
  * @brief This is the internal base class for all controls.
  *
@@ -617,18 +618,47 @@ public: // API for derived classes to override
     return NULL;
   }
 
-  // Transition
+  // Transition APIs
+
+  /**
+   * @brief Make visual transition from source control to destination control about specific Visual.
+   * If both of source and destination control have same visual index, than generates information for the transition of this Control.
+   *
+   * @param[out] sourcePropertyMap Source property map to be applied on this Control.
+   * @param[out] destinationPropertyMap Destination property map to be applied on this Control.
+   * @param[in] source Source control of the animation.
+   * @param[in] destination Destination control of the animation.
+   * @param[in] visualIndex Property::Index to make animation.
+   */
+  void MakeVisualTransition(Dali::Property::Map& sourcePropertyMap, Dali::Property::Map& destinationPropertyMap,
+                            Dali::Toolkit::Control source, Dali::Toolkit::Control destination, Dali::Property::Index visualIndex);
 
   /**
-   * @brief Retrieve visual property animations.
-   * This Control is a destination.
+   * @brief Retrieves source and destination visual properties for the Transition of this Control.
+   * The properties of this Control will be transitioned from the propeties of source Control to that of destination control.
+   * If a property value is different between source and destination Control,
+   * the property information of each Control will be included in sourceProperties and destinationProperties.
+   *
+   * @param[out] sourceProperties Source property list to be applied on this Control.
+   * @param[out] destinationProperties Destination property list to be applied on this Control.
+   * @param[in] source Source control of the animation.
+   * @param[in] destination Destination control of the animation.
    *
-   * @param[in] animation generated animation
-   * @param[in] source source control of the animation.
-   * @param[in] alphaFunction AlphaFunction of the animation
-   * @param[in] timePeriod TimePeriod of the animation
+   * @note This method do not handle Actor properties.
+   * And the size and order of the sourceProperties and destinationProperties must be synchronized.
+   */
+  virtual void OnCreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
+                                   std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
+                                   Dali::Toolkit::Control                                              source,
+                                   Dali::Toolkit::Control                                              destination)
+  {
+  }
+
+  /**
+   * @brief Update visual properties.
+   * @param[in] properties Property list to be used to update visual properties of this Control.
    */
-  virtual void OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
+  virtual void OnUpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
   {
   }
 
index b5f6a8c..958d031 100644 (file)
@@ -51,9 +51,9 @@ GlView GlView::DownCast(BaseHandle handle)
   return Control::DownCast<GlView, Internal::GlView>(handle);
 }
 
-void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+void GlView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
 {
-  Dali::Toolkit::GetImpl(*this).RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback);
+  Dali::Toolkit::GetImpl(*this).RegisterGlCallbacks(initCallback, renderFrameCallback, terminateCallback);
 }
 
 void GlView::SetResizeCallback(CallbackBase* resizeCallback)
index be13db9..57c3201 100644 (file)
@@ -165,7 +165,7 @@ public:
    * <b>You can't call Dali APIs in your callbacks because it is invoked in GlView's own render thread.</b>
    * And this must be called before adding GlView to the scene.
    */
-  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+  void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
 
   /**
    * @brief Sets the ResizeCallback of the GlView.
index 9935284..5f6856e 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 48;
+const unsigned int TOOLKIT_MICRO_VERSION = 52;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 3e2f378..57f7364 100644 (file)
@@ -32,9 +32,9 @@ Transition::Transition(Internal::Transition* transition)
 {
 }
 
-Transition Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+Transition Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, bool useDestinationTarget, TimePeriod timePeriod)
 {
-  Internal::TransitionPtr internal = Dali::Toolkit::Internal::Transition::New(source, destination, timePeriod);
+  Internal::TransitionPtr internal = Dali::Toolkit::Internal::Transition::New(source, destination, useDestinationTarget, timePeriod);
 
   return Transition(internal.Get());
 }
index 634face..fa27fa6 100644 (file)
@@ -51,13 +51,14 @@ public:
   /**
    * @brief Creates an initialized Transition.
    *
-   * @param[in] source Source
-   * @param[in] destination Destination
+   * @param[in] source A source control of this transition.
+   * @param[in] destination A destination control of this transition.
+   * @param[in] useDestinationTarget True if this transition uses destination control as target.
    * @param[in] timePeriod The duration in seconds
    * @return A handle to a newly allocated Dali resource
    * @note durationSeconds can not be negative.
    */
-  static Transition New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod);
+  static Transition New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, bool useDestinationTarget, TimePeriod timePeriod);
 
   /**
    * @brief Downcasts a handle to Transition handle.
diff --git a/dali-toolkit/styles/1920x1080_rpi/dali-toolkit-default-theme.json b/dali-toolkit/styles/1920x1080_rpi/dali-toolkit-default-theme.json
new file mode 100644 (file)
index 0000000..d862b80
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 1920x1080 resolution, The values determined by UX design specification.
+// This file can be copied to a new folder within the styles/ directory and amended with new default values.
+// Can be overriden if StyleManager applies another style sheet.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png",
+    "alwaysShowFocus":true,
+    "clearFocusOnEscape":false
+  },
+  "styles":
+  {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":24
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
+    "TextLabel":
+    {
+      "pointSize":24,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80,
+      "ignoreSpacesAfterText":false
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":24
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":28
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":32
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":36
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":40
+    },
+
+    "TextField":
+    {
+      "pointSize":28,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":false
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":24
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":28
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":32
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":36
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":40
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[1700,100],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "rendererType": "image",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":24
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[1920.0,130.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png"
+      },
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[1920.0,130.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[1920.0,130.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "TextEditor":
+    {
+      "pointSize":24,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":false
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 12.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "CircularProgressBar":
+    {
+      "size":[64,64],
+      "trackVisual":{
+        "visualType":"ARC",
+        "mixColor":[0.0,0.165,0.302,1.0],
+        "thickness":4.0,
+        "startAngle":0.0,
+        "cap":"ROUND"
+      },
+      "progressVisual":{
+        "visualType":"ARC",
+        "mixColor":[0.0,0.549,1.0,1.0],
+        "thickness":4.0,
+        "startAngle":0.0,
+        "cap":"ROUND"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"ARC",
+        "mixColor":[0.0,0.549,1.0,0.3],
+        "thickness":4.0,
+        "startAngle":0.0,
+        "cap":"ROUND"
+      },
+      "indeterminateVisual":{
+        "visualType":"ARC",
+        "mixColor":[0.02,0.71,0.525,1.0],
+        "thickness":4.0,
+        "startAngle":267.0,
+        "sweepAngle":75.0,
+        "cap":"ROUND"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"trackVisual",
+          "property":"opacity",
+          "targetValue": 0,
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0,
+              "delay":0
+            }
+          }
+        },
+        {
+          "target":"secondaryProgressVisual",
+          "property":"opacity",
+          "targetValue": 0,
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0,
+              "delay":0
+            }
+          }
+        },
+        {
+          "target":"progressVisual",
+          "property":"sweepAngle",
+          "initialValue": 75,
+          "targetValue": 180,
+          "animator":
+          {
+            "alphaFunction":[0.439, 0.0, 0.718, 0.428],
+            "timePeriod":
+            {
+              "duration":1.0,
+              "delay":0.0
+            }
+          }
+        },
+        {
+          "target":"progressVisual",
+          "property":"sweepAngle",
+          "targetValue": 75,
+          "animator":
+          {
+            "alphaFunction":[0.224, 0.571, 0.53, 1.0],
+            "timePeriod":
+            {
+              "duration":1.0,
+              "delay":2.0
+            }
+          }
+        },
+        {
+          "target":"progressVisual",
+          "property":"startAngle",
+          "initialValue": 87,
+          "targetValue": 1887,
+          "animator":
+          {
+            "alphaFunction":[0.33, 0.0, 0.3, 1.0],
+            "timePeriod":
+            {
+              "duration":3.0,
+              "delay":0.0
+            }
+          }
+        },
+        {
+          "target":"indeterminateVisual",
+          "property":"sweepAngle",
+          "initialValue": 75,
+          "targetValue": 180,
+          "animator":
+          {
+            "alphaFunction":[0.439, 0.0, 0.718, 0.428],
+            "timePeriod":
+            {
+              "duration":1.0,
+              "delay":0.0
+            }
+          }
+        },
+        {
+          "target":"indeterminateVisual",
+          "property":"sweepAngle",
+          "targetValue": 75,
+          "animator":
+          {
+            "alphaFunction":[0.224, 0.571, 0.53, 1.0],
+            "timePeriod":
+            {
+              "duration":1.0,
+              "delay":2.0
+            }
+          }
+        },
+        {
+          "target":"indeterminateVisual",
+          "property":"startAngle",
+          "initialValue": 267,
+          "targetValue": 2067,
+          "animator":
+          {
+            "alphaFunction":[0.33, 0.0, 0.3, 1.0],
+            "timePeriod":
+            {
+              "duration":3.0,
+              "delay":0.0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 32.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.2,
+      "secondaryProgressValue":0.4,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "styles":["Tooltip"],
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "styles":["Button"],
+      "autoRepeating":false,
+      "togglable":false,
+      "labelPadding":[ 12.0, 12.0, 12.0, 12.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "horizontalAlignment": "CENTER",
+         "pointSize" : 24.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-up.9.png"
+       },
+       "selectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down.9.png"
+       },
+       "disabledSelectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down-disabled.9.png"
+       },
+       "disabledUnselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-disabled.9.png"
+       }
+    },
+    "ToggleButton":
+    {
+      "styles":["Button"]
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 24.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 24.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/1920x1080_rpi/images/cursor_handler_drop_center.png b/dali-toolkit/styles/1920x1080_rpi/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080_rpi/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_left.png b/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_right.png b/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080_rpi/images/selection_handle_drop_right.png differ
index 1cf7e71..d9a1c86 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.0.48
+Version:    2.0.52
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT
@@ -34,6 +34,7 @@ Requires:   %{name} = %{version}-%{release}
 Conflicts:  %{name}-resources_480x800
 Conflicts:  %{name}-resources_720x1280
 Conflicts:  %{name}-resources_1920x1080
+Conflicts:  %{name}-resources_1920x1080_rpi
 %description resources_360x360
 dali-toolkit default resource files for 360x360
 Contain po / sounds / common images / style / style images
@@ -44,6 +45,7 @@ Requires:   %{name} = %{version}-%{release}
 Conflicts:  %{name}-resources_360x360
 Conflicts:  %{name}-resources_720x1280
 Conflicts:  %{name}-resources_1920x1080
+Conflicts:  %{name}-resources_1920x1080_rpi
 %description resources_480x800
 dali-toolkit default resource files for 480x800
 Contain po / sounds / common images / style / style images
@@ -54,6 +56,7 @@ Requires:   %{name} = %{version}-%{release}
 Conflicts:  %{name}-resources_360x360
 Conflicts:  %{name}-resources_480x800
 Conflicts:  %{name}-resources_1920x1080
+Conflicts:  %{name}-resources_1920x1080_rpi
 %description resources_720x1280
 dali-toolkit default resource files for 720x1280
 Contain po / sounds / common images / style / style images
@@ -64,10 +67,23 @@ Requires:   %{name} = %{version}-%{release}
 Conflicts:  %{name}-resources_360x360
 Conflicts:  %{name}-resources_480x800
 Conflicts:  %{name}-resources_720x1280
+Conflicts:  %{name}-resources_1920x1080_rpi
 %description resources_1920x1080
 dali-toolkit default resource files for 1920x1080
 Contain po / sounds / common images / style / style images
 
+%package resources_1920x1080_rpi
+Summary:    default resource files for 1920x1080 on Raspberry Pi 4
+Requires:   %{name} = %{version}-%{release}
+Conflicts:  %{name}-resources_360x360
+Conflicts:  %{name}-resources_480x800
+Conflicts:  %{name}-resources_720x1280
+Conflicts:  %{name}-resources_1920x1080
+%description resources_1920x1080_rpi
+dali-toolkit default resource files for 1920x1080 on Raspberry Pi 4
+Contain po / sounds / common images / style / style images
+
+
 ##############################
 # devel
 ##############################
@@ -199,6 +215,8 @@ mkdir -p %{buildroot}%{dali_toolkit_style_files}/720x1280
 cp -r dali-toolkit/styles/720x1280/* %{buildroot}%{dali_toolkit_style_files}/720x1280
 mkdir -p %{buildroot}%{dali_toolkit_style_files}/1920x1080
 cp -r dali-toolkit/styles/1920x1080/* %{buildroot}%{dali_toolkit_style_files}/1920x1080
+mkdir -p %{buildroot}%{dali_toolkit_style_files}/1920x1080_rpi
+cp -r dali-toolkit/styles/1920x1080_rpi/* %{buildroot}%{dali_toolkit_style_files}/1920x1080_rpi
 
 # Copy default feedback theme
 cp dali-toolkit/styles/default-feedback-theme.json %{buildroot}%{dali_toolkit_style_files}
@@ -244,6 +262,15 @@ case "$1" in
   ;;
 esac
 
+%pre resources_1920x1080_rpi
+case "$1" in
+  2)
+    pushd %{dali_toolkit_style_files}
+    rm -rf ./*
+    popd
+  ;;
+esac
+
 ##############################
 # Post Install
 ##############################
@@ -271,6 +298,11 @@ pushd %{dali_toolkit_style_files}/1920x1080
 for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
 popd
 
+%post resources_1920x1080_rpi
+pushd %{dali_toolkit_style_files}/1920x1080_rpi
+for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
+popd
+
 ##############################
 # Pre Uninstall
 ##############################
@@ -319,6 +351,17 @@ case "$1" in
   ;;
 esac
 
+%preun resources_1920x1080_rpi
+case "$1" in
+  0)
+    %preun resources_1920x1080_rpi
+    pushd %{dali_toolkit_style_files}
+    mv images ./1920x1080_rpi
+    mv dali-toolkit-default-theme.json ./1920x1080_rpi
+    popd
+  ;;
+esac
+
 ##############################
 # Post Uninstall
 ##############################
@@ -362,6 +405,15 @@ case "$1" in
   ;;
 esac
 
+%postun resources_1920x1080_rpi
+case "$1" in
+  0)
+    pushd %{dali_toolkit_style_files}
+    rm -rf *
+    popd
+  ;;
+esac
+
 ##############################
 # Files in Binary Packages
 ##############################
@@ -417,6 +469,15 @@ esac
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 
+%files resources_1920x1080_rpi
+%manifest dali-toolkit-resources.manifest
+%defattr(-,root,root,-)
+%{dali_toolkit_image_files}/*
+%{dali_toolkit_sound_files}/*
+%{dali_toolkit_style_files}/1920x1080_rpi/*
+%{dali_toolkit_style_files}/default-feedback-theme.json
+%{_datadir}/locale/*/LC_MESSAGES/*
+
 %files -n %{dali2_scene_loader}
 %if 0%{?enable_dali_smack_rules}
 %manifest dali-scene-loader.manifest-smack