Merge "TableView: Enum cleanup and Complete the SetCellAlignment() func" into devel...
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Thu, 25 Jun 2015 09:20:36 +0000 (02:20 -0700)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Thu, 25 Jun 2015 09:20:36 +0000 (02:20 -0700)
automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
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/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 6d8ddff..164ab9e 100644 (file)
@@ -115,6 +115,10 @@ int UtcDaliBuilderAnimationP(void)
   // JSON with a quit event when the actor is touched
   std::string json(
         "{"
+        "   \"constants\":"
+        "   {"
+        "     \"ALPHA_FUNCTION\":\"EASE_IN_OUT\""
+        "   },"
         "   \"paths\":"
         "   {"
         "     \"path0\":"
@@ -133,7 +137,7 @@ int UtcDaliBuilderAnimationP(void)
         "        \"actor\": \"greeting\","
         "        \"property\": \"position\","
         "        \"value\": [300, 300, -1000],"
-        "        \"alpha-function\": \"EASE_IN_OUT\","
+        "        \"alpha-function\": \"{ALPHA_FUNCTION}\","
         "        \"relative\": true,"
         "        \"time-period\": {"
         "          \"delay\": 0,"
@@ -248,6 +252,12 @@ int UtcDaliBuilderAnimationP(void)
 
   DALI_TEST_CHECK( anim );
 
+  Property::Map map;
+  map["ALPHA_FUNCTION"] = "EASE_IN_SQUARE";
+  anim = builder.CreateAnimation("animate", map);
+
+  DALI_TEST_CHECK( anim );
+
   anim = builder.CreateAnimation("path-animation");
 
   DALI_TEST_CHECK( anim );
@@ -273,6 +283,11 @@ int UtcDaliBuilderAnimationN(void)
   // JSON with a quit event when the actor is touched
   std::string json(
         "{"
+        "   \"constants\":"
+        "   {"
+        "     \"TEXT\": \"Touch Me\","
+        "     \"NAME\": \"greeting\" "
+        "   },"
         "   \"paths\":"
         "   {"
         "     \"path0\":"
@@ -288,7 +303,7 @@ int UtcDaliBuilderAnimationN(void)
         "      \"disconnect-action\": \"BAKE\","
         "      \"properties\":"
         "      [{"
-        "        \"actor\": \"greeting\","
+        "        \"actor\": \"{NAME}\","
         "        \"property\": \"positioninvalid\","
         "        \"value\": [300, 300, -1000],"
         "        \"alpha-function\": \"EASE_IN_OUT\","
@@ -306,7 +321,7 @@ int UtcDaliBuilderAnimationN(void)
         "      \"disconnect-action\": \"BAKE\","
         "      \"properties\":"
         "      [{"
-        "        \"actor\": \"greeting\","
+        "        \"actor\": \"{NAME}\","
         "        \"property\": \"positioninvalid\","
         "        \"value\": [300, 300, -1000],"
         "        \"alpha-function\": \"EGGS_OVER_EASY\","
@@ -347,6 +362,11 @@ int UtcDaliBuilderAnimationN(void)
         "      \"action\": \"play\","
         "      \"animation\": \"animate\""
         "    }]"
+        "  },"
+        "  {"
+        "    \"name\": \"greeting2\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\""
         "  }]"
         "}");
 
@@ -359,12 +379,28 @@ int UtcDaliBuilderAnimationN(void)
 
   // log warning line coverage
   anim = builder.CreateAnimation("path-animation");
+  DALI_TEST_CHECK(anim);
 
   anim = builder.CreateAnimation("animate");
+  DALI_TEST_CHECK(anim);
 
   anim = builder.CreateAnimation("animate2");
+  DALI_TEST_CHECK(anim);
+
+  // create referencing a different actor aka animation templates
+  Property::Map map;
+  map["NAME"] = "greeting2";
+  anim = builder.CreateAnimation("animate2", map);
+  DALI_TEST_CHECK(anim);
+
+  // alternative actor to use for FindChildByName
+  anim = builder.CreateAnimation("animate2", Dali::Stage::GetCurrent().GetRootLayer());
+  DALI_TEST_CHECK(anim);
+
+  // alternative actor to use for FindChildByName
+  anim = builder.CreateAnimation("animate2", map, Dali::Stage::GetCurrent().GetRootLayer());
+  DALI_TEST_CHECK(anim);
 
-  DALI_TEST_CHECK(true);
 
   END_TEST;
 
@@ -387,6 +423,7 @@ int UtcDaliBuilderConstantsP(void)
       "\"stage\":"
       "[{"
       "  \"type\": \"ImageActor\","
+      "  \"name\": \"{NAME}\","
       "  \"size\": [100,100,1],"
       "  \"parent-origin\": \"TOP_LEFT\","
       "  \"anchor-point\": \"{ANCHOR}\","
@@ -403,9 +440,29 @@ int UtcDaliBuilderConstantsP(void)
 
   Builder builder = Builder::New();
   builder.LoadFromString( json );
+
+  builder.AddConstant( "NAME", "image" );
+
+  Property::Map map = builder.GetConstants();
+
+  Dali::Property::Value* pValue = map.Find( "NAME" );
+
+  DALI_TEST_CHECK( pValue );
+
+  pValue = map.Find( "IMAGE_PATH" );
+
+  DALI_TEST_CHECK( pValue );
+
+  Dali::Property::Value value = builder.GetConstant( "WIDTH" );
+
+  DALI_TEST_CHECK( value.GetType() != Property::NONE );
+
   builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
   DALI_TEST_CHECK( builder );
 
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("image");
+  DALI_TEST_CHECK( actor );
+
   END_TEST;
 }
 
@@ -416,6 +473,10 @@ int UtcDaliBuilderTemplatesAndStylesP(void)
   // JSON with a quit event when the actor is touched
   std::string json(
       "{\n"
+      "\"constants\":"
+      "{"
+      "  \"SIZE\": [10,20,30]"
+      "},"
       "\"styles\":\n"
       "{\n"
       "  \"image-style\": \n"
@@ -434,7 +495,7 @@ int UtcDaliBuilderTemplatesAndStylesP(void)
       "    \"type\": \"ImageActor\",\n"
       "    \"styles\": [\"image-style\"],\n"
       "    \"name\": \"image\",\n"
-      "    \"size\": [100,100,1],\n"
+      "    \"size\": \"{SIZE}\",\n"
       "    \"signals\": [{\n"
       "      \"name\": \"touched\",\n"
       "      \"action\": \"quit\"\n"
@@ -446,19 +507,67 @@ int UtcDaliBuilderTemplatesAndStylesP(void)
       "      }\n"
       "    ]\n"
       "  }\n"
-      "}\n"
+      "},\n"
+      "\"stage\":"
+      "[{"
+      "  \"type\": \"image-tree\","
+      "  \"size\": [100,100,1]"
+      "}]"
       "}\n"
   );
 
+  std::string stylejson(
+    "{\n"
+    " \"color\": [1,0,0,1],\n"
+    " \"actors\": {\n"
+    "   \"child-image\": {\n"
+    "     \"color\": [0,1,0,1]\n"
+    "   }\n"
+    " }\n"
+    "}\n"
+    );
+
+  std::string templatejson(
+    "{ \n"
+    "  \"type\": \"ImageActor\",\n"
+    "  \"styles\": [\"image-style\"],\n"
+    "  \"name\": \"image\",\n"
+    "  \"size\": \"{SIZE}\",\n"
+    "  \"signals\": [{\n"
+    "    \"name\": \"touched\",\n"
+    "    \"action\": \"quit\"\n"
+    "  }],\n"
+    "  \"actors\": [\n"
+    "    {\n"
+    "      \"type\":\"ImageActor\",\n"
+    "      \"name\":\"child-image\" \n"
+    "    }\n"
+    "  ]\n"
+    "}\n"
+    );
+
   Builder builder = Builder::New();
   builder.LoadFromString( json );
 
   ImageActor actor = ImageActor::DownCast( builder.Create( "image-tree" ) );
   DALI_TEST_CHECK( actor );
 
+  Dali::Property::Map map;
+  map["SIZE"] = Vector3(100,100,1);
+  actor = ImageActor::DownCast( builder.Create( "image-tree", map ) );
+  DALI_TEST_CHECK( actor );
+
+  // create from json snippet
+  actor = ImageActor::DownCast( builder.CreateFromJson( templatejson ) );
+  DALI_TEST_CHECK( actor );
+
+
   // NB: already applied in create
   DALI_TEST_CHECK( builder.ApplyStyle( "image-style", actor ) );
 
+  // apply from json snippet
+  DALI_TEST_CHECK( builder.ApplyFromJson( actor, stylejson ) );
+
   END_TEST;
 }
 
@@ -732,3 +841,617 @@ int UtcDaliBuilderPropertyNotificationP(void)
 
   END_TEST;
 }
+
+int UtcDaliBuilderCustomPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "\"templates\":\n"
+      "{\n"
+      "  \"image-tree\": { \n"
+      "    \"type\": \"ImageActor\",\n"
+      "    \"name\": \"image\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"quit\"\n"
+      "    }],\n"
+      "    \"custom-properties\": {\n"
+      "      \"newproperty\": true\n"
+      "    },\n"
+      "    \"actors\": [\n"
+      "      {\n"
+      "        \"type\":\"ImageActor\",\n"
+      "        \"name\":\"child-image\" \n"
+      "      }\n"
+      "    ]\n"
+      "  }\n"
+      "}\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  ImageActor actor = ImageActor::DownCast( builder.Create( "image-tree" ) );
+  DALI_TEST_CHECK( actor );
+
+  // NB: already applied in create
+  Property::Index index = actor.GetPropertyIndex("newproperty");
+  DALI_TEST_CHECK( Property::INVALID_INDEX != index );
+  Property::Value value = actor.GetProperty(index);
+  DALI_TEST_CHECK( value.Get<bool>() == true );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderShaderEffectP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"ImageActor\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"position\": [\n"
+    "        0.40461349487305,\n"
+    "        0.9150390625,\n"
+    "        0.0\n"
+    "      ],\n"
+    "      \"parent-origin\": [0.5, 0.5, 0.5],\n"
+    "      \"size\": [200, 200, 0],\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": {\n"
+    "        \"filename\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\",\n"
+    "        \"width\": 200,\n"
+    "        \"height\": 80,\n"
+    "        \"load-policy\": \"IMMEDIATE\",\n"
+    "        \"release-policy\": \"NEVER\"\n"
+    "      },\n"
+    "      \"signals\": [\n"
+    "        {\n"
+    "          \"name\": \"on-stage\",\n"
+    "          \"action\": \"play\",\n"
+    "          \"animation\": \"Animation_1\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  ],\n"
+    "  \"paths\": {},\n"
+    "  \"animations\": {\n"
+    "    \"Animation_1\": {\n"
+    "      \"loop\":true,\n"
+    "      \"properties\": [\n"
+    "        {\n"
+    "          \"actor\": \"Image1\",\n"
+    "          \"property\": \"uTime\",\n"
+    "          \"value\": 10.0,\n"
+    "          \"alpha-function\": \"LINEAR\",\n"
+    "          \"time-period\": {\n"
+    "            \"delay\": 0,\n"
+    "            \"duration\": 10.0\n"
+    "          },\n"
+    "          \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  },\n"
+    "  \"shader-effects\": {\n"
+    "    \"Ripple2D\": {\n"
+    "      \"program\": {\n"
+    "        \"vertexPrefix\": \"\",\n"
+    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
+    "        \"fragmentPrefix\": \"\",\n"
+    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
+    "        \"geometry-type\": \"GEOMETRY_TYPE_IMAGE\"\n"
+    "      },\n"
+    "      \"geometry-hints\": \"HINT_NONE\",\n"
+    "      \"grid-density\": 0,\n"
+    "      \"loop\": true,\n"
+    "      \"uAmplitude\": 0.02,\n"
+    "      \"uTime\": 0.0\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  ShaderEffect effect = builder.GetShaderEffect("Ripple2D");
+
+  // coverage
+  DALI_TEST_CHECK( effect );
+
+  END_TEST;
+}
+
+
+int UtcDaliBuilderLoadFromStringN(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "asdfsadf dsf asdf asdf {"
+         "\"stage\":"
+         "[{"
+           "\"type\": \"Actor\","
+           "\"size\": [100,100,1],"
+           "\"parent-origin\": \"TOP_LEFT\","
+           "\"anchor-point\": \"TOP_LEFT\","
+           "\"signals\": [{"
+             "\"name\": \"touched\","
+             "\"action\": \"quit\""
+           "}]"
+         "}]"
+      "}"
+  );
+  Builder builder = Builder::New();
+
+  bool assert1 = false;
+
+  try
+  {
+    builder.LoadFromString( json );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "!\"Cannot parse JSON\"", TEST_LOCATION);
+    assert1 = true;
+  }
+
+  DALI_TEST_CHECK( assert1 );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderShaderEffect2P(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "\"templates\":\n"
+    "{\n"
+    "  \"image-tree\": { \n"
+    "    \"type\": \"ImageActor\",\n"
+    "    \"size\": [100,100,1],\n"
+    "    \"parent-origin\": [0.5, 0.5, 0.5],\n"
+    "    \"position\": [\n"
+    "      0.40461349487305,\n"
+    "      0.9150390625,\n"
+    "      0.0\n"
+    "    ],\n"
+    "    \"signals\": [{\n"
+    "      \"name\": \"touched\",\n"
+    "      \"action\": \"quit\"\n"
+    "    }],\n"
+    "    \"actors\": [\n"
+    "      {\n"
+    "        \"type\":\"ImageActor\",\n"
+    "        \"name\":\"child-image\" \n"
+    "      }\n"
+    "    ]\n"
+    "  }\n"
+    "},\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"image-tree\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": \"offscreen\""
+    "    }\n"
+    "  ],\n"
+    "  \"shader-effects\": {\n"
+    "    \"Ripple2D\": {\n"
+    "      \"program\": {\n"
+    "        \"vertexPrefix\": \"\",\n"
+    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
+    "        \"fragmentPrefix\": \"\",\n"
+    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
+    "        \"geometry-type\": \"GEOMETRY_TYPE_IMAGE\"\n"
+    "      },\n"
+    "      \"geometry-hints\": \"HINT_NONE\",\n"
+    "      \"grid-density\": 0,\n"
+    "      \"loop\": true,\n"
+    "      \"uAmplitude\": 0.02,\n"
+    "      \"uTime\": 0.0\n"
+    "    }\n"
+    "  },\n"
+    "  \"frame-buffer-images\": {\n"
+    "    \"offscreen\": {\n"
+    "      \"type\": \"FrameBufferImage\","
+    "      \"pixel-format\":\"RGBA8888\","
+    "      \"width\": 400,"
+    "      \"height\": 400"
+    "    }"
+    "   }"
+    "}\n"
+
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  // coverage
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderAddActorsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"arbitarysection\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parent-origin\": \"TOP_LEFT\",\n"
+      "    \"anchor-point\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"sub-actor\",\n"
+      "      \"visible\": false\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"hide\",\n"
+      "      \"actor\": \"actor\",\n"
+      "      \"child-actor\": \"sub-actor\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( "arbitarysection", Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("sub-actor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderFrameBufferP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"FB_WIDTH\": 200.0,\n"
+    "    \"FB_HEIGHT\": 200.0,\n"
+    "    \"FB_SIZE\": [200,200],\n"
+    "    \"FB_ASPECT_RATIO\": 1\n"
+    "  },\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"ImageActor\",\n"
+    "      \"name\": \"fbOnStage\",\n"
+    "      \"position\": [\n"
+    "        0.40461349487305,\n"
+    "        0.9150390625,\n"
+    "        0.0\n"
+    "      ],\n"
+    "      \"parent-origin\": [0.5, 0.5, 0.5],\n"
+    "      \"size\": [300, 300, 0],\n"
+    "      \"image\": \"fb0\",\n"
+    "      \"clear-color\": [1,0,0,1]\n"
+    "    },\n"
+    "    {\n"
+    "      \"type\": \"ImageActor\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"size\": [200, 200, 0],\n"
+    "      \"parent-origin\": [0.5, 0.5, 0.5],\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": {\n"
+    "        \"filename\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\",\n"
+    "        \"width\": 200,\n"
+    "        \"height\": 80,\n"
+    "        \"load-policy\": \"IMMEDIATE\",\n"
+    "        \"release-policy\": \"NEVER\"\n"
+    "      },\n"
+    "      \"signals\": [\n"
+    "        {\n"
+    "          \"name\": \"on-stage\",\n"
+    "          \"action\": \"play\",\n"
+    "          \"animation\": \"Animation_1\"\n"
+    "        }\n"
+    "      ]\n"
+    "    },\n"
+    "    {\n"
+    "      \"type\":\"CameraActor\",\n"
+    "      \"name\":\"fbCam\",\n"
+    "      \"aspect-ratio\": \"{FB_ASPECT_RATIO}\",\n"
+    "      \"projection-mode\": \"PERSPECTIVE_PROJECTION\",\n"
+    "      \"field-of-view\": 0.785,\n"
+    "      \"invert-y-axis\": true\n"
+    "    }\n"
+    "  ],\n"
+    "  \"frame-buffer-images\":\n"
+    "  {\n"
+    "    \"fb0\":\n"
+    "    {\n"
+    "      \"type\": \"FrameBufferImage\",\n"
+    "      \"width\": { \"type-cast\":\"float\", \"value\":\"{FB_WIDTH}\" },\n"
+    "      \"height\": { \"type-cast\":\"float\", \"value\":\"{FB_HEIGHT}\" }\n"
+    "    }\n"
+    "  },\n"
+    "  \"render-tasks\":\n"
+    "  {\n"
+    "    \"stage\":\n"
+    "    [\n"
+    "      {\n"
+    "        \"source-actor\": \"fbOnStage\"\n"
+    "      },\n"
+    "      {\n"
+    "        \"source-actor\": \"Image1\",\n"
+    "        \"target-frame-buffer\": \"fb0\",\n"
+    "        \"viewport-size\":\"{FB_SIZE}\",\n"
+    "        \"camera-actor\":\"fbCam\"\n"
+    "      }\n"
+    "    ]\n"
+    "  },\n"
+    "  \"paths\": {},\n"
+    "  \"animations\": {\n"
+    "    \"Animation_1\": {\n"
+    "      \"loop\":true,\n"
+    "      \"properties\": [\n"
+    "        {\n"
+    "          \"actor\": \"Image1\",\n"
+    "          \"property\": \"uTime\",\n"
+    "          \"value\": 10.0,\n"
+    "          \"alpha-function\": \"LINEAR\",\n"
+    "          \"time-period\": {\n"
+    "            \"delay\": 0,\n"
+    "            \"duration\": 10.0\n"
+    "          },\n"
+    "          \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  },\n"
+    "  \"shader-effects\": {\n"
+    "    \"Ripple2D\": {\n"
+    "      \"program\": {\n"
+    "        \"vertexPrefix\": \"\",\n"
+    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
+    "        \"fragmentPrefix\": \"\",\n"
+    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
+    "        \"geometry-type\": \"GEOMETRY_TYPE_IMAGE\"\n"
+    "      },\n"
+    "      \"geometry-hints\": \"HINT_NONE\",\n"
+    "      \"grid-density\": 0,\n"
+    "      \"loop\": true,\n"
+    "      \"uAmplitude\": 0.02,\n"
+    "      \"uTime\": 0.0\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+
+  Builder builder = Builder::New();
+
+  // frame buffer coverage
+  builder.LoadFromString( json );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Dali::FrameBufferImage frameBuffer = builder.GetFrameBufferImage( "fb0" );
+  DALI_TEST_CHECK( frameBuffer );
+
+  Dali::FrameBufferImage frameBuffer2 = builder.GetFrameBufferImage( "fb0" );
+  DALI_TEST_CHECK( frameBuffer2 );
+  DALI_TEST_CHECK( frameBuffer == frameBuffer2 );
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderPathConstraintsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"FB_WIDTH\": 200.0,\n"
+    "    \"FB_HEIGHT\": 200.0,\n"
+    "    \"FB_SIZE\": [200,200],\n"
+    "    \"FB_ASPECT_RATIO\": 1\n"
+    "  },\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"ImageActor\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"size\": [200, 200, 0],\n"
+    "      \"parent-origin\": [0.5, 0.5, 0.5],\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": {\n"
+    "        \"filename\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\",\n"
+    "        \"width\": 200,\n"
+    "        \"height\": 80,\n"
+    "        \"load-policy\": \"IMMEDIATE\",\n"
+    "        \"release-policy\": \"NEVER\"\n"
+    "      },\n"
+    "      \"signals\": [\n"
+    "        {\n"
+    "          \"name\": \"on-stage\",\n"
+    "          \"action\": \"play\",\n"
+    "          \"animation\": \"path-animation\"\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"on-stage\",\n"
+    "          \"action\": \"applyConstraint\",\n"
+    "          \"constrainer\": \"constrainer0\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"position-x\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"color-red\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"on-stage\",\n"
+    "          \"action\": \"applyConstraint\",\n"
+    "          \"constrainer\": \"constrainer1\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"position-x\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"color-blue\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  ],\n"
+    "  \"paths\":\n"
+    "  {\n"
+    "    \"path0\":\n"
+    "    {\n"
+    "      \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],\n"
+    "      \"curvature\":0.35\n"
+    "    }\n"
+    "  },\n"
+    "  \"constrainers\":\n"
+    "  {\n"
+    "    \"constrainer0\":\n"
+    "    {\n"
+    "      \"type\": \"PathConstrainer\",\n"
+    "      \"points\": [ [0, 0, 0], [0,0,0], [0,0,0] ],\n"
+    "      \"control-points\": [ [0, 0, 0], [0,0,0], [0,0,0] ]\n"
+    "    },\n"
+    "    \"constrainer1\":\n"
+    "    {\n"
+    "      \"type\": \"LinearConstrainer\",\n"
+    "      \"value\": [ 0, 0, 0 ]\n"
+    "    }\n"
+    "  },\n"
+    "  \"animations\": {\n"
+    "    \"path-animation\": {\n"
+    "      \"duration\": 3.0,\n"
+    "      \"properties\":\n"
+    "      [{\n"
+    "        \"actor\": \"Image1\",\n"
+    "        \"path\":\"path0\",\n"
+    "        \"forward\":[1,0,0],\n"
+    "        \"alpha-function\": \"EASE_IN_OUT\",\n"
+    "        \"time-period\": {\n"
+    "          \"delay\": 0,\n"
+    "          \"duration\": 3\n"
+    "        }\n"
+    "      },\n"
+    "       {\n"
+    "         \"actor\": \"Image1\",\n"
+    "         \"property\": \"uTime\",\n"
+    "         \"value\": 10.0,\n"
+    "         \"alpha-function\": \"LINEAR\",\n"
+    "         \"time-period\": {\n"
+    "           \"delay\": 0,\n"
+    "           \"duration\": 10.0\n"
+    "         },\n"
+    "         \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "       }]\n"
+    "    },\n"
+    "    \"Animation_1\": {\n"
+    "      \"loop\":true,\n"
+    "      \"properties\": [\n"
+    "        {\n"
+    "          \"actor\": \"Image1\",\n"
+    "          \"property\": \"uTime\",\n"
+    "          \"value\": 10.0,\n"
+    "          \"alpha-function\": \"LINEAR\",\n"
+    "          \"time-period\": {\n"
+    "            \"delay\": 0,\n"
+    "            \"duration\": 10.0\n"
+    "          },\n"
+    "          \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  },\n"
+    "  \"shader-effects\": {\n"
+    "    \"Ripple2D\": {\n"
+    "      \"program\": {\n"
+    "        \"vertexPrefix\": \"\",\n"
+    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
+    "        \"fragmentPrefix\": \"\",\n"
+    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
+    "        \"geometry-type\": \"GEOMETRY_TYPE_IMAGE\"\n"
+    "      },\n"
+    "      \"geometry-hints\": \"HINT_NONE\",\n"
+    "      \"grid-density\": 0,\n"
+    "      \"loop\": true,\n"
+    "      \"uAmplitude\": 0.02,\n"
+    "      \"uTime\": 0.0\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+
+  Builder builder = Builder::New();
+
+  // frame buffer coverage
+  builder.LoadFromString( json );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Dali::Path path =  builder.GetPath( "path0" );
+  DALI_TEST_CHECK( path );
+
+  Dali::Path path2 =  builder.GetPath( "path0" );
+  DALI_TEST_CHECK( path2 );
+  DALI_TEST_CHECK( path == path2 );
+
+  Dali::PathConstrainer constrainer0 = builder.GetPathConstrainer( "constrainer0" );
+  DALI_TEST_CHECK( constrainer0 );
+
+  Dali::PathConstrainer constrainer0_2 = builder.GetPathConstrainer( "constrainer0" );
+  DALI_TEST_CHECK( constrainer0_2 );
+  DALI_TEST_CHECK( constrainer0 == constrainer0_2 );
+
+  Dali::LinearConstrainer constrainer1 = builder.GetLinearConstrainer( "constrainer1" );
+  DALI_TEST_CHECK( constrainer1 );
+
+  Dali::LinearConstrainer constrainer1_2 = builder.GetLinearConstrainer( "constrainer1" );
+  DALI_TEST_CHECK( constrainer1 == constrainer1_2 );
+
+  END_TEST;
+}
index 02de592..31c62c5 100644 (file)
@@ -235,6 +235,7 @@ struct Decorator::Impl : public ConnectionTracker
     mTextSelectionPopupCallbackInterface( callbackInterface ),
     mBoundingBox( Rect<int>() ),
     mHighlightColor( LIGHT_BLUE ),
+    mHighlightPosition( Vector2::ZERO ),
     mActiveCursor( ACTIVE_CURSOR_NONE ),
     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
     mCursorBlinkDuration( 0.0f ),
@@ -247,7 +248,8 @@ struct Decorator::Impl : public ConnectionTracker
     mCursorBlinkStatus( true ),
     mPrimaryCursorVisible( false ),
     mSecondaryCursorVisible( false ),
-    mSwapSelectionHandles( false )
+    mSwapSelectionHandles( false ),
+    mNotifyEndOfScroll( false )
   {
   }
 
@@ -269,17 +271,6 @@ struct Decorator::Impl : public ConnectionTracker
       if( mPrimaryCursorVisible )
       {
         Vector2 position = cursor.position;
-        if( GRAB_HANDLE == mHandleScrolling )
-        {
-          if( mScrollDirection == SCROLL_RIGHT )
-          {
-            position.x = 0.f;
-          }
-          else
-          {
-            position.x = size.width;
-          }
-        }
 
         mPrimaryCursor.SetPosition( position.x,
                                     position.y );
@@ -306,18 +297,6 @@ struct Decorator::Impl : public ConnectionTracker
     {
       Vector2 position = grabHandle.position;
 
-      if( GRAB_HANDLE == mHandleScrolling )
-      {
-        if( mScrollDirection == SCROLL_RIGHT )
-        {
-          position.x = 0.f;
-        }
-        else
-        {
-          position.x = size.width;
-        }
-      }
-
       const bool isVisible = ( position.x <= size.width ) && ( position.x >= 0.f );
 
       if( isVisible )
@@ -344,29 +323,6 @@ struct Decorator::Impl : public ConnectionTracker
       Vector2 primaryPosition = primary.position;
       Vector2 secondaryPosition = secondary.position;
 
-      if( LEFT_SELECTION_HANDLE == mHandleScrolling )
-      {
-        if( mScrollDirection == SCROLL_RIGHT )
-        {
-          primaryPosition.x = 0.f;
-        }
-        else
-        {
-          primaryPosition.x = size.width;
-        }
-      }
-      else if( RIGHT_SELECTION_HANDLE == mHandleScrolling )
-      {
-        if( mScrollDirection == SCROLL_RIGHT )
-        {
-          secondaryPosition.x = 0.f;
-        }
-        else
-        {
-          secondaryPosition.x = size.width;
-        }
-      }
-
       const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
       const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
 
@@ -866,8 +822,10 @@ struct Decorator::Impl : public ConnectionTracker
     else if( Gesture::Finished  == gesture.state ||
              Gesture::Cancelled == gesture.state )
     {
-      if( mScrollTimer && mScrollTimer.IsRunning() )
+      if( mScrollTimer &&
+          ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
       {
+        mNotifyEndOfScroll = false;
         mHandleScrolling = HANDLE_TYPE_COUNT;
         StopScrollTimer();
         mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
@@ -1155,6 +1113,16 @@ struct Decorator::Impl : public ConnectionTracker
     return mScrollSpeed;
   }
 
+  void NotifyEndOfScroll()
+  {
+    StopScrollTimer();
+
+    if( mScrollTimer )
+    {
+      mNotifyEndOfScroll = true;
+    }
+  }
+
   /**
    * Creates and starts a timer to scroll the text when handles are close to the edges of the text.
    *
@@ -1228,10 +1196,10 @@ struct Decorator::Impl : public ConnectionTracker
   CursorImpl          mCursor[CURSOR_COUNT];
   HandleImpl          mHandle[HANDLE_TYPE_COUNT];
   QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight
-  Vector2             mHighlightPosition;         ///< The position of the highlight actor.
 
   Rect<int>           mBoundingBox;
   Vector4             mHighlightColor;            ///< Color of the highlight
+  Vector2             mHighlightPosition;         ///< The position of the highlight actor.
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
@@ -1241,13 +1209,13 @@ struct Decorator::Impl : public ConnectionTracker
   float               mScrollThreshold;         ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
   float               mScrollSpeed;             ///< The scroll speed in pixels per second.
   float               mScrollDistance;          ///< Distance the text scrolls during a scroll interval.
-  unsigned int        mScrollInterval;          ///< Time in milliseconds of a scroll interval.
 
   bool                mActiveCopyPastePopup   : 1;
   bool                mCursorBlinkStatus      : 1; ///< Flag to switch between blink on and blink off.
   bool                mPrimaryCursorVisible   : 1; ///< Whether the primary cursor is visible.
   bool                mSecondaryCursorVisible : 1; ///< Whether the secondary cursor is visible.
   bool                mSwapSelectionHandles   : 1; ///< Whether to swap the selection handle images.
+  bool                mNotifyEndOfScroll      : 1; ///< Whether to notify the end of the scroll.
 };
 
 DecoratorPtr Decorator::New( ControllerInterface& controller,
@@ -1481,6 +1449,11 @@ float Decorator::GetScrollSpeed() const
   return mImpl->GetScrollSpeed();
 }
 
+void Decorator::NotifyEndOfScroll()
+{
+  mImpl->NotifyEndOfScroll();
+}
+
 Decorator::~Decorator()
 {
   delete mImpl;
index 893d981..f38c467 100644 (file)
@@ -467,18 +467,9 @@ public:
   float GetScrollSpeed() const;
 
   /**
-   * @brief Sets the scroll interval.
-   *
-   * @param[in] seconds The scroll interval in seconds.
-   */
-  void SetScrollTickInterval( float seconds );
-
-  /**
-   * @brief Retrieves the scroll interval.
-   *
-   * @return The scroll interval.
+   * @brief Notifies the decorator the whole text has been scrolled.
    */
-  float GetScrollTickInterval() const;
+  void NotifyEndOfScroll();
 
 protected:
 
index f05ffda..7a51b86 100644 (file)
@@ -569,7 +569,8 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     {
       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
 
-      if( handleNewPosition != mEventData->mLeftSelectionPosition )
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
 
@@ -583,7 +584,8 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     {
       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
 
-      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
 
@@ -625,12 +627,13 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       if( handleStopScrolling )
       {
-        mEventData->mUpdateLeftSelectionPosition = mEventData->mLeftSelectionPosition != handlePosition;
+        mEventData->mUpdateLeftSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition);
         mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
-        mEventData->mLeftSelectionPosition = handlePosition;
 
         if( mEventData->mUpdateLeftSelectionPosition )
         {
+          mEventData->mLeftSelectionPosition = handlePosition;
+
           RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
                                       mEventData->mRightSelectionPosition );
         }
@@ -642,12 +645,12 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       if( handleStopScrolling )
       {
-        mEventData->mUpdateRightSelectionPosition = mEventData->mRightSelectionPosition != handlePosition;
+        mEventData->mUpdateRightSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
         mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
-        mEventData->mRightSelectionPosition = handlePosition;
 
         if( mEventData->mUpdateRightSelectionPosition )
         {
+          mEventData->mRightSelectionPosition = handlePosition;
           RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
                                       mEventData->mRightSelectionPosition );
         }
@@ -660,50 +663,80 @@ void Controller::Impl::OnHandleEvent( const Event& event )
   {
     const float xSpeed = event.p2.mFloat;
     const Vector2& actualSize = mVisualModel->GetActualSize();
+    const Vector2 currentScrollPosition = mEventData->mScrollPosition;
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
-    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
-    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
-
-    if( Event::GRAB_HANDLE_EVENT == event.type )
+    if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
     {
-      ChangeState( EventData::GRAB_HANDLE_PANNING );
+      // Notify the decorator there is no more text to scroll.
+      // The decorator won't send more scroll events.
+      mEventData->mDecorator->NotifyEndOfScroll();
     }
-    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+    else
     {
-      // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
-      //       Think if something can be done to save power.
+      const bool scrollRightDirection = xSpeed > 0.f;
+      const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+      const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
 
-      ChangeState( EventData::SELECTION_HANDLE_PANNING );
+      if( Event::GRAB_HANDLE_EVENT == event.type )
+      {
+        ChangeState( EventData::GRAB_HANDLE_PANNING );
 
-      const Vector2& position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+        Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
 
-      // Get the new handle position.
-      // The selection handle's position is in decorator coords. Need to transforms to text coords.
-      const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
-                                                                   position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+        // Position the grag handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mControlSize.width;
 
-      if( leftSelectionHandleEvent )
-      {
-        mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
-        mEventData->mLeftSelectionPosition = handlePosition;
+        // Get the new handle position.
+        // The grab handle's position is in decorator coords. Need to transforms to text coords.
+        const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                     position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+        mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
+        mEventData->mPrimaryCursorPosition = handlePosition;
       }
-      else
+      else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
       {
-        mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
-        mEventData->mRightSelectionPosition = handlePosition;
-      }
+        // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
+        //       Think if something can be done to save power.
 
-      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
-      {
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
+        ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+        Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+        // Position the selection handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mControlSize.width;
+
+        // Get the new handle position.
+        // The selection handle's position is in decorator coords. Need to transforms to text coords.
+        const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                     position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+        if( leftSelectionHandleEvent )
+        {
+          mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+        else
+        {
+          mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+
+        if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+        {
+          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                      mEventData->mRightSelectionPosition );
+
+          mEventData->mScrollAfterUpdatePosition = true;
+        }
       }
+      mEventData->mDecoratorUpdated = true;
     }
-    mEventData->mDecoratorUpdated = true;
   } // end ( HANDLE_SCROLLING == state )
 }
 
@@ -721,12 +754,17 @@ void Controller::Impl::OnSelectEvent( const Event& event )
     const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
     const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
+    const CharacterIndex leftPosition = mEventData->mLeftSelectionPosition;
+    const CharacterIndex rightPosition = mEventData->mRightSelectionPosition;
+
     RepositionSelectionHandles( xPosition,
                                 yPosition );
 
-    mEventData->mScrollAfterUpdatePosition = true;
-    mEventData->mUpdateLeftSelectionPosition = true;
-    mEventData->mUpdateRightSelectionPosition = true;
+    mEventData->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
+    mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+
+    mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
+                                               ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
   }
 }
 
@@ -749,7 +787,7 @@ void Controller::Impl::OnSelectAllEvent()
   }
 }
 
-void Controller::Impl::RetreiveSelection( std::string& selectedText, bool deleteAfterRetreival )
+void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetreival )
 {
   if( mEventData->mLeftSelectionPosition ==  mEventData->mRightSelectionPosition )
   {
@@ -794,7 +832,7 @@ bool Controller::Impl::CopyStringToClipboard( std::string& source )
 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
 {
   std::string selectedText;
-  RetreiveSelection( selectedText, deleteAfterSending );
+  RetrieveSelection( selectedText, deleteAfterSending );
   CopyStringToClipboard( selectedText );
   ChangeState( EventData::EDITING );
 }
index 8e84d3c..880004a 100644 (file)
@@ -339,7 +339,7 @@ struct Controller::Impl
 
   void OnSelectAllEvent();
 
-  void RetreiveSelection( std::string& selectedText, bool deleteAfterRetreival );
+  void RetrieveSelection( std::string& selectedText, bool deleteAfterRetreival );
 
   bool CopyStringToClipboard( std::string& source );
 
index f1ee352..b55a543 100644 (file)
@@ -1121,9 +1121,6 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
     int keyCode = keyEvent.keyCode;
     const std::string& keyString = keyEvent.keyPressed;
 
-    // Hide the grab handle.
-    mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-
     // Pre-process to separate modifying events from non-modifying input events.
     if( Dali::DALI_KEY_ESCAPE == keyCode )
     {
@@ -1141,29 +1138,7 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
     }
     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
     {
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
-
-      // IMF manager is no longer handling key-events
-      mImpl->ClearPreEditFlag();
-
-      // Remove the character before the current cursor position
-      bool removed = RemoveText( -1, 1 );
-
-      if( removed )
-      {
-        if( 0u != mImpl->mLogicalModel->mText.Count() ||
-            !mImpl->IsPlaceholderAvailable() )
-        {
-          mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
-        }
-        else
-        {
-          ShowPlaceholderText();
-          mImpl->mEventData->mUpdateCursorPosition = true;
-        }
-
-        textChanged = true;
-      }
+      textChanged = BackspaceKeyEvent();
     }
     else
     {
@@ -1173,7 +1148,6 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->ClearPreEditFlag();
 
       InsertText( keyString, COMMIT );
-
       textChanged = true;
     }
 
@@ -1193,7 +1167,7 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
 
 void Controller::InsertText( const std::string& text, Controller::InsertType type )
 {
-  bool removedPreEdit( false );
+  bool removedPrevious( false );
   bool maxLengthReached( false );
 
   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
@@ -1210,11 +1184,16 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
       0 != mImpl->mEventData->mPreEditLength )
   {
     CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
-    removedPreEdit = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
+    removedPrevious = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
 
     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
     mImpl->mEventData->mPreEditLength = 0;
   }
+  else
+  {
+    // Remove the previous Selection
+    removedPrevious = RemoveSelectedText();
+  }
 
   if( ! text.empty() )
   {
@@ -1299,7 +1278,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     mImpl->mEventData->mUpdateCursorPosition = true;
     mImpl->ClearPreEditFlag();
   }
-  else if( removedPreEdit ||
+  else if( removedPrevious ||
            0 != utf32Characters.Count() )
   {
     // Queue an inserted event
@@ -1317,6 +1296,26 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   }
 }
 
+bool Controller::RemoveSelectedText()
+{
+  bool textRemoved( false );
+
+  if ( EventData::SELECTING         == mImpl->mEventData->mState ||
+       EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+  {
+    std::string removedString;
+    mImpl->RetrieveSelection( removedString, true );
+
+    if( !removedString.empty() )
+    {
+      textRemoved = true;
+      mImpl->ChangeState( EventData::EDITING );
+    }
+  }
+
+  return textRemoved;
+}
+
 void Controller::TapEvent( unsigned int tapCount, float x, float y )
 {
   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
@@ -1501,7 +1500,7 @@ void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Butt
     {
       std::string stringToPaste("");
       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
-      InsertText( stringToPaste, Text::Controller::CLIPBOARD );
+      InsertText( stringToPaste, Text::Controller::COMMIT );
       mImpl->ChangeState( EventData::EDITING );
       mImpl->RequestRelayout();
       break;
@@ -1606,6 +1605,43 @@ Controller::~Controller()
   delete mImpl;
 }
 
+bool Controller::BackspaceKeyEvent()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
+
+  // IMF manager is no longer handling key-events
+  mImpl->ClearPreEditFlag();
+
+  bool removed( false );
+
+  if ( EventData::SELECTING         == mImpl->mEventData->mState ||
+       EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+  {
+    removed = RemoveSelectedText();
+  }
+  else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
+  {
+    // Remove the character before the current cursor position
+    removed = RemoveText( -1, 1 );
+  }
+
+  if( removed )
+  {
+    if( 0u != mImpl->mLogicalModel->mText.Count() ||
+        !mImpl->IsPlaceholderAvailable() )
+    {
+      mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+    }
+    else
+    {
+      ShowPlaceholderText();
+      mImpl->mEventData->mUpdateCursorPosition = true;
+    }
+  }
+
+  return removed;
+}
+
 void Controller::ShowPlaceholderText()
 {
   if( mImpl->IsPlaceholderAvailable() )
index f1e1d28..2f83407 100644 (file)
@@ -103,8 +103,7 @@ public:
   enum InsertType
   {
     COMMIT,
-    PRE_EDIT,
-    CLIPBOARD
+    PRE_EDIT
   };
 
   /**
@@ -504,6 +503,12 @@ public:
   void InsertText( const std::string& text, InsertType type );
 
   /**
+   * @brief Checks if text is selected and if so removes it.
+   * @return true if text was removed
+   */
+  bool RemoveSelectedText();
+
+  /**
    * @brief Called by editable UI controls when a tap gesture occurs.
    * @param[in] tapCount The number of taps.
    * @param[in] x The x position relative to the top-left of the parent control.
@@ -569,6 +574,13 @@ protected:
 private:
 
   /**
+   * @brief Helper to KeyEvent() to handle the backspace case.
+   *
+   * @return True if a character was deleted.
+   */
+  bool BackspaceKeyEvent();
+
+  /**
    * @brief Helper to clear font-specific data.
    */
   void ShowPlaceholderText();
index 38e9672..aed0470 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 45;
+const unsigned int TOOLKIT_MICRO_VERSION = 46;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 6ba1b7f..c804f61 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.0.45
+Version:    1.0.46
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0