Merge branch 'devel/master' into devel/new_mesh 13/42313/3
authorFrancisco Santos <f1.santos@samsung.com>
Thu, 25 Jun 2015 14:23:06 +0000 (15:23 +0100)
committerFrancisco Santos <f1.santos@samsung.com>
Fri, 26 Jun 2015 12:55:46 +0000 (13:55 +0100)
Conflicts:
automated-tests/src/dali-toolkit/CMakeLists.txt
dali-toolkit/devel-api/shader-effects/distance-field-effect.cpp
dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp
dali-toolkit/internal/atlas-manager/atlas-manager-impl.h
dali-toolkit/internal/atlas-manager/atlas-manager.cpp
dali-toolkit/internal/atlas-manager/atlas-manager.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/public-api/controls/control-impl.cpp

Change-Id: I48b90c6c4696dbc7b65659ecf6004a09a17c7ab0

103 files changed:
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/utc-Dali-PushButton.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-BloomView.cpp
automated-tests/src/dali-toolkit/utc-Dali-BubbleEmitter.cpp
automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ItemView.cpp
automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp
build/tizen/configure.ac
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/controls/magnifier/magnifier.cpp
dali-toolkit/devel-api/controls/magnifier/magnifier.h
dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.cpp
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h
dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h [new file with mode: 0644]
dali-toolkit/devel-api/file.list
dali-toolkit/images/selection-popup-bg#.png [new file with mode: 0755]
dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp
dali-toolkit/internal/atlas-manager/atlas-manager-impl.h
dali-toolkit/internal/atlas-manager/atlas-manager.cpp
dali-toolkit/internal/atlas-manager/atlas-manager.h
dali-toolkit/internal/builder/builder-actor.cpp
dali-toolkit/internal/builder/builder-animations.cpp
dali-toolkit/internal/builder/builder-impl.cpp
dali-toolkit/internal/builder/builder-set-property.cpp
dali-toolkit/internal/controls/alignment/alignment-impl.cpp
dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp
dali-toolkit/internal/controls/magnifier/magnifier-impl.h
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
dali-toolkit/internal/controls/slider/slider-impl.cpp
dali-toolkit/internal/controls/table-view/table-view-impl.cpp
dali-toolkit/internal/controls/table-view/table-view-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h
dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/focus-manager/accessibility-focus-manager-impl.cpp
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/text/bidirectional-support.cpp
dali-toolkit/internal/text/bidirectional-support.h
dali-toolkit/internal/text/character-set-conversion.cpp
dali-toolkit/internal/text/character-set-conversion.h
dali-toolkit/internal/text/clipping/text-clipper.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-engine.h
dali-toolkit/internal/text/line-run.h
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/multi-language-support-impl.cpp
dali-toolkit/internal/text/multi-language-support-impl.h
dali-toolkit/internal/text/multi-language-support.cpp
dali-toolkit/internal/text/multi-language-support.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/segmentation.cpp
dali-toolkit/internal/text/segmentation.h
dali-toolkit/internal/text/shaper.cpp
dali-toolkit/internal/text/shaper.h
dali-toolkit/internal/text/text-control-interface.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/internal/text/text-view.cpp
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/control-impl.h
dali-toolkit/public-api/controls/default-controls/solid-color-actor.cpp
dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h
dali-toolkit/public-api/controls/scrollable/item-view/item-view.cpp
dali-toolkit/public-api/controls/scrollable/item-view/item-view.h
dali-toolkit/public-api/controls/table-view/table-view.cpp
dali-toolkit/public-api/controls/table-view/table-view.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/styles/dali-toolkit-default-theme.json
dali-toolkit/styles/mobile/dali-toolkit-default-theme.json
packaging/dali-toolkit.spec
plugins/dali-script-v8/src/object/property-value-wrapper.cpp

index 8011f6a..9324e48 100644 (file)
@@ -8,6 +8,9 @@ SET(CAPI_LIB "dali-toolkit-internal")
 # List of test case sources (Only these get parsed for test cases)
 SET(TC_SOURCES
  utc-Dali-PushButton.cpp
+ utc-Dali-Text-CharacterSetConversion.cpp
+ utc-Dali-Text-Segmentation.cpp
+ utc-Dali-Text-MultiLanguage.cpp
 )
 
 # Append list of test harness files (Won't get parsed for test cases)
index 7d1ef18..e23dbe3 100644 (file)
@@ -689,53 +689,5 @@ int UtcDaliPushButtonProperties(void)
   DALI_TEST_CHECK( button.IsSelected() ) ;
   DALI_TEST_CHECK( button.GetProperty< bool >( Button::Property::SELECTED ) );
 
-  //  Button::PROPERTY_NORMAL_STATE_ACTOR
-  {
-    button.SetButtonImage( ResourceImage::New( "IMAGE_PATH_1") );
-    DALI_TEST_EQUALS( "IMAGE_PATH_1", button.GetProperty( Button::Property::NORMAL_STATE_ACTOR ).GetValue( "image" ).GetValue( "filename" ).Get< std::string >(), TEST_LOCATION );
-
-    Property::Map map;
-    map[ "type" ] = "ImageActor";
-
-    button.SetProperty( Button::Property::NORMAL_STATE_ACTOR, map );
-    DALI_TEST_EQUALS( "ImageActor", button.GetProperty( Button::Property::NORMAL_STATE_ACTOR ).GetValue( "type" ).Get< std::string >(), TEST_LOCATION );
-  }
-
-  //  Button::PROPERTY_SELECTED_STATE_ACTOR
-  {
-    button.SetSelectedImage( ResourceImage::New( "IMAGE_PATH_2") );
-    DALI_TEST_EQUALS( "IMAGE_PATH_2", button.GetProperty( Button::Property::SELECTED_STATE_ACTOR ).GetValue( "image" ).GetValue( "filename" ).Get< std::string >(), TEST_LOCATION );
-
-    Property::Map map;
-    map[ "type" ] = "Actor";
-
-    button.SetProperty( Button::Property::SELECTED_STATE_ACTOR, map );
-    DALI_TEST_EQUALS( "Actor", button.GetProperty( Button::Property::SELECTED_STATE_ACTOR ).GetValue( "type" ).Get< std::string >(), TEST_LOCATION );
-    DALI_TEST_CHECK( "ImageActor" != button.GetProperty( Button::Property::SELECTED_STATE_ACTOR ).GetValue( "type" ).Get< std::string >() );
-  }
-
-  //  Button::PROPERTY_DISABLED_STATE_ACTOR
-  {
-    button.SetDisabledImage( ResourceImage::New( "IMAGE_PATH_3") );
-    DALI_TEST_EQUALS( "IMAGE_PATH_3", button.GetProperty( Button::Property::DISABLED_STATE_ACTOR ).GetValue( "image" ).GetValue( "filename" ).Get< std::string >(), TEST_LOCATION );
-
-    Property::Map map;
-    map[ "type" ] = "Actor";
-
-    button.SetProperty( Button::Property::DISABLED_STATE_ACTOR, map );
-    DALI_TEST_EQUALS( "Actor", button.GetProperty( Button::Property::DISABLED_STATE_ACTOR ).GetValue( "type" ).Get< std::string >(), TEST_LOCATION );
-  }
-
-  //  Button::PROPERTY_LABEL_ACTOR
-  {
-    button.SetLabel( "LABEL_TEXT_CUSTOM" );
-    DALI_TEST_EQUALS( "TextLabel", button.GetProperty( Button::Property::LABEL_ACTOR ).GetValue( "type" ).Get< std::string >(), TEST_LOCATION );
-
-    Property::Map map;
-    map[ "type" ] = "Actor";
-
-    button.SetProperty( Button::Property::LABEL_ACTOR, map );
-    DALI_TEST_EQUALS( "Actor", button.GetProperty( Button::Property::LABEL_ACTOR ).GetValue( "type" ).Get< std::string >(), TEST_LOCATION );
-  }
   END_TEST;
 }
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp
new file mode 100644 (file)
index 0000000..9f816ef
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015 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 <iostream>
+
+#include <stdlib.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions for scripts with different number of bytes per character.
+// Latin 1 byte per character, Arabic 2 bytes per character, Devanagari 3 bytes per character and emojis 4 bytes per character.
+//
+// uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length );
+// uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters );
+// uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 );
+// uint32_t Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 );
+//     void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std::string& utf8 );
+//
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct GetNumberOfUtf8CharactersData
+{
+  std::string  description;        ///< Description of the test.
+  std::string  text;               ///< input text.
+  unsigned int numberOfCharacters; ///< The expected number of characters.
+};
+
+bool GetNumberOfUtf8CharactersTest( const GetNumberOfUtf8CharactersData& data )
+{
+  return GetNumberOfUtf8Characters( reinterpret_cast<const uint8_t*>( data.text.c_str() ), data.text.size() ) == data.numberOfCharacters;
+}
+
+//////////////////////////////////////////////////////////
+
+struct GetNumberOfUtf8BytesData
+{
+  std::string   description;        ///< Description of the test.
+  unsigned int* utf32;              ///< input text in utf32.
+  unsigned int  numberOfCharacters; ///< The number of characters.
+  unsigned int  numberOfBytes;      ///< The expected number of bytes in utf8.
+};
+
+bool GetNumberOfUtf8BytesTest( const GetNumberOfUtf8BytesData& data )
+{
+  return GetNumberOfUtf8Bytes( data.utf32, data.numberOfCharacters ) == data.numberOfBytes;
+}
+
+//////////////////////////////////////////////////////////
+
+struct Utf8ToUtf32Data
+{
+  std::string   description; ///< Description of the test.
+  std::string   text;        ///< input text.
+  unsigned int* utf32;       ///< The expected text (array of bytes with text encoded in utf32).
+};
+
+
+bool Utf8ToUtf32Test( const Utf8ToUtf32Data& data )
+{
+  Vector<uint32_t> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   utf32.Begin() );
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    if( data.utf32[index] != utf32[index] )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+struct Utf32ToUtf8Data
+{
+  std::string   description;        ///< Description of the test.
+  unsigned int* utf32;              ///< The input text (array of bytes with text encoded in utf32).
+  unsigned int  numberOfCharacters; ///< The number of characters.
+  std::string   text;               ///< The expected text.
+};
+
+bool Utf32ToUtf8Test( const Utf32ToUtf8Data& data )
+{
+  std::string text;
+
+  Utf32ToUtf8( data.utf32, data.numberOfCharacters, text );
+
+  return text == data.text;
+}
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextCharacterSetConversionGetNumberOfUtf8Characters(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Characters");
+
+  const GetNumberOfUtf8CharactersData data[] =
+  {
+    {
+      "Latin script",
+      "Hello World",
+      11u,
+    },
+    {
+      "Arabic script",
+      "مرحبا بالعالم",
+      13u,
+    },
+    {
+      "Devanagari script",
+      "हैलो वर्ल्ड",
+      11u,
+    },
+    {
+      "Emojis",
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+      7u,
+    },
+  };
+  const unsigned int numberOfTests = 4u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetNumberOfUtf8CharactersTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes");
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_03[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_04[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+
+  const GetNumberOfUtf8BytesData data[] =
+  {
+    {
+      "Latin script",
+      utf32_01,
+      11u,
+      11u,
+    },
+    {
+      "Arabic script",
+      utf32_02,
+      13u,
+      25u,
+    },
+    {
+      "Devanagari script",
+      utf32_03,
+      11u,
+      31u,
+    },
+    {
+      "Emojis",
+      utf32_04,
+      7u,
+      19u,
+    },
+  };
+  const unsigned int numberOfTests = 4u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetNumberOfUtf8BytesTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionUtf8ToUtf32(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes");
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_03[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_04[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+
+  const Utf8ToUtf32Data data[] =
+  {
+    {
+      "Latin script",
+      "Hello World",
+      utf32_01,
+    },
+    {
+      "Arabic script",
+      "مرحبا بالعالم",
+      utf32_02,
+    },
+    {
+      "Devanagari script",
+      "हैलो वर्ल्ड",
+      utf32_03,
+    },
+    {
+      "Emojis",
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+      utf32_04,
+    },
+  };
+  const unsigned int numberOfTests = 4u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !Utf8ToUtf32Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionUtf32ToUtf8(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionUtf32ToUtf8");
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_03[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_04[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+
+  struct Utf32ToUtf8Data data[] =
+  {
+    {
+      "Latin script",
+      utf32_01,
+      11u,
+      "Hello World",
+    },
+    {
+      "Arabic script",
+      utf32_02,
+      13u,
+      "مرحبا بالعالم",
+    },
+    {
+      "Devanagari script",
+      utf32_03,
+      11u,
+      "हैलो वर्ल्ड",
+    },
+    {
+      "Emojis",
+      utf32_04,
+      7u,
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+    },
+  };
+
+  const unsigned int numberOfTests = 4u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !Utf32ToUtf8Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp
new file mode 100644 (file)
index 0000000..4b89f25
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2015 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 <iostream>
+
+#include <stdlib.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions with different scripts.
+// Constructor, destructor and MultilanguageSupport::Get()
+// void MultilanguageSupport::SetScripts( const Vector<Character>& text, const Vector<LineBreakInfo>& lineBreakInfo, Vector<ScriptRun>& scripts );
+// void MultilanguageSupport::ValidateFonts( const Vector<Character>& text, const Vector<ScriptRun>& scripts, Vector<FontRun>& fonts );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct ScriptsData
+{
+  std::string description;      ///< Description of the experiment.
+  std::string text;             ///< Input text.
+  Vector<ScriptRun> scriptRuns; ///< Expected script runs.
+};
+
+struct ValidateFontsData
+{
+  std::string description;  ///< Description of the experiment.
+  std::string text;         ///< Input text.
+};
+
+//////////////////////////////////////////////////////////
+
+bool ScriptsTest( const ScriptsData& data )
+{
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   &utf32[0u] );
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the line break info.
+  Vector<LineBreakInfo> lineBreakInfo;
+  lineBreakInfo.Resize( numberOfCharacters );
+
+  SetLineBreakInfo( utf32, lineBreakInfo );
+
+  // 3) Set the script info.
+  Vector<ScriptRun> scripts;
+  multilanguageSupport.SetScripts( utf32,
+                                   lineBreakInfo,
+                                   scripts );
+
+  // 4) Compare the results.
+
+  if( scripts.Count() != data.scriptRuns.Count() )
+  {
+    tet_infoline("ScriptsTest: different number of scripts.");
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < scripts.Count(); ++index )
+  {
+    const ScriptRun& scriptRun1 = scripts[index];
+    const ScriptRun& scriptRun2 = data.scriptRuns[index];
+
+    if( scriptRun1.characterRun.characterIndex != scriptRun2.characterRun.characterIndex )
+    {
+      tet_infoline("ScriptsTest: different character index.");
+      return false;
+    }
+
+    if( scriptRun1.characterRun.numberOfCharacters != scriptRun2.characterRun.numberOfCharacters )
+    {
+      tet_infoline("ScriptsTest: different number of characters.");
+      return false;
+    }
+
+    if( scriptRun1.script != scriptRun2.script )
+    {
+      tet_infoline("ScriptsTest: different script.");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ValidateFontTest( const ValidateFontsData& data )
+{
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   &utf32[0u] );
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the line break info.
+  Vector<LineBreakInfo> lineBreakInfo;
+  lineBreakInfo.Resize( numberOfCharacters );
+
+  SetLineBreakInfo( utf32, lineBreakInfo );
+
+  // 3) Set the script info.
+  Vector<ScriptRun> scripts;
+  multilanguageSupport.SetScripts( utf32,
+                                   lineBreakInfo,
+                                   scripts );
+
+  Vector<FontRun> fonts;
+  // 4) Validate the fonts
+  multilanguageSupport.ValidateFonts( utf32,
+                                      scripts,
+                                      fonts );
+
+  return true;
+}
+
+} // namespace
+
+int UtcDaliTextMultiLanguageConstructor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageConstructor");
+
+  MultilanguageSupport multilanguageSupport;
+  DALI_TEST_CHECK( !multilanguageSupport );
+
+  MultilanguageSupport multilanguageSupport1 = MultilanguageSupport::Get();
+  DALI_TEST_CHECK( multilanguageSupport1 );
+
+  // To increase coverage.
+  MultilanguageSupport multilanguageSupport2 = MultilanguageSupport::Get();
+  DALI_TEST_CHECK( multilanguageSupport2 );
+
+  DALI_TEST_CHECK( multilanguageSupport1 == multilanguageSupport2 );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMultiLanguageSetScripts(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageSetScripts" );
+
+  // Void text.
+  Vector<ScriptRun> scriptRuns00;
+
+  // Hello world.
+  Vector<ScriptRun> scriptRuns01;
+  ScriptRun scriptRun0100 =
+  {
+    0u,
+    11u,
+    TextAbstraction::LATIN
+  };
+  scriptRuns01.PushBack( scriptRun0100 );
+
+  const ScriptsData data[] =
+  {
+    {
+      "void text",
+      "",
+      scriptRuns00,
+    },
+    {
+      "Easy latin script",
+      "Hello world",
+      scriptRuns01,
+    },
+  };
+  const unsigned int numberOfTests = 2u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ScriptsTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMultiLanguageValidateFonts01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageValidateFonts");
+
+  const ValidateFontsData data[] =
+  {
+    {
+      "void text",
+      "",
+    },
+    {
+      "Easy latin script",
+      "Hello world",
+    },
+  };
+  const unsigned int numberOfTests = 2u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ValidateFontTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp
new file mode 100644 (file)
index 0000000..2e60ee5
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015 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 <iostream>
+
+#include <stdlib.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions with different scripts.
+// void SetLineBreakInfo( const Vector<Character>& text, Vector<LineBreakInfo>& lineBreakInfo );
+// void SetWordBreakInfo( const Vector<Character>& text, Vector<WordBreakInfo>& wordBreakInfo );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct BreakInfoData
+{
+  std::string description; ///< Description of the test.
+  std::string text;        ///< input text.
+  std::string breakInfo;   ///< The expected break info.
+};
+
+bool LineBreakInfoTest( const BreakInfoData& data )
+{
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   &utf32[0u] );
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the line break info.
+  Vector<LineBreakInfo> lineBreakInfo;
+  lineBreakInfo.Resize( numberOfCharacters );
+
+  SetLineBreakInfo( utf32, lineBreakInfo );
+
+  // 3) compare the results
+  std::ostringstream breakInfo;
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    breakInfo << static_cast<unsigned int>( lineBreakInfo[index] );
+  }
+
+  return data.breakInfo == breakInfo.str();
+}
+
+bool WordBreakInfoTest( const BreakInfoData& data )
+{
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   &utf32[0u] );
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the word break info.
+  Vector<WordBreakInfo> wordBreakInfo;
+  wordBreakInfo.Resize( numberOfCharacters );
+
+  SetWordBreakInfo( utf32, wordBreakInfo );
+
+  // 3) compare the results
+  std::ostringstream breakInfo;
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    breakInfo << static_cast<unsigned int>( wordBreakInfo[index] );
+  }
+
+  return data.breakInfo == breakInfo.str();
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextSegnemtationSetLineBreakInfo(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextSegnemtationSetLineBreakInfo");
+
+  struct BreakInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      "",
+    },
+    {
+      "Latin script",
+      "Hello world",
+      "22222122220",
+    },
+    {
+      "Latin script with \n",
+      "Hello\nworld",
+      "22222022220",
+    },
+    {
+      "Japanese script",
+      "こんにちは世界",
+      "1111110",
+    },
+    {
+      "Japanese script with \n",
+      "こんにちは\n世界",
+      "11112010",
+    },
+    {
+      "Chinese script",
+      "你好世界",
+      "1110",
+    },
+    {
+      "Chinese script with \n",
+      "你好\n世界",
+      "12010",
+    }
+  };
+  const unsigned int numberOfTests = 7u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !LineBreakInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextSegnemtationSetWordBreakInfo(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextSegnemtationSetWordBreakInfo");
+
+  struct BreakInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      "",
+    },
+    {
+      "Latin script",
+      "Hello world",
+      "11110011110",
+    },
+    {
+      "Latin script with \n",
+      "Hello\nworld",
+      "11110011110",
+    },
+    {
+      "Japanese script",
+      "こんにちは世界",
+      "0000000",
+    },
+    {
+      "Japanese script with \n",
+      "こんにちは\n世界",
+      "00000000",
+    },
+    {
+      "Chinese script",
+      "你好世界",
+      "0000",
+    },
+    {
+      "Chinese script with \n",
+      "你好\n世界",
+      "00000",
+    }
+  };
+  const unsigned int numberOfTests = 7u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !WordBreakInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index 9217cd0..bdf225c 100644 (file)
@@ -13,6 +13,7 @@ SET(TC_SOURCES
    utc-Dali-Builder.cpp
    utc-Dali-CheckBoxButton.cpp
    utc-Dali-CubeTransitionEffect.cpp
+   utc-Dali-EffectsView.cpp
    utc-Dali-GaussianBlurView.cpp
    utc-Dali-JsonParser.cpp
    utc-Dali-KeyInputFocusManager.cpp
@@ -35,6 +36,7 @@ SET(TC_SOURCES
    utc-Dali-ItemLayout.cpp
    utc-Dali-ItemView.cpp
    utc-Dali-KeyboardFocusManager.cpp
+   utc-Dali-Magnifier.cpp
    utc-Dali-NinePatchMaskEffect.cpp
    utc-Dali-Popup.cpp
    utc-Dali-PushButton.cpp
index c35269a..fa3f10c 100644 (file)
@@ -164,3 +164,63 @@ int UtcDaliBloomActivateDeactivate(void)
   DALI_TEST_CHECK( 1u == taskList3.GetTaskCount() );
   END_TEST;
 }
+
+int UtcDaliBloomCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  BloomView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  BloomView assign;
+  DALI_TEST_CHECK( ! assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliBloomTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "BloomView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  BloomView view = BloomView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliBloomOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+
+  BloomView view = Toolkit::BloomView::New();
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 200.0f );
+  view.SetSize( size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION );
+
+  END_TEST;
+}
index ca864c2..2140f2a 100644 (file)
@@ -215,8 +215,12 @@ int UtcDaliBubbleEmitterSetBubbleScale(void)
 
   Image shapeImage = CreateSolidColorImage( application, Color::GREEN, 5, 5 );
   BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 150, Vector2( 5.f, 10.f ));
+  DALI_TEST_CHECK(emitter);
   Actor root = emitter.GetRootActor();
   Stage::GetCurrent().Add( root );
+  root.SetPosition( Vector3::ZERO );
+  root.SetParentOrigin( ParentOrigin::CENTER );
+  root.SetAnchorPoint( AnchorPoint::CENTER );
 
   TestGlAbstraction& gl = application.GetGlAbstraction();
 
@@ -235,6 +239,7 @@ int UtcDaliBubbleEmitterSetBubbleScale(void)
   Wait(application);
   DALI_TEST_CHECK( gl.GetUniformValue<float>( "uDynamicScale", scaleValue ) );
   DALI_TEST_EQUALS( scaleValue, 0.5f, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -286,8 +291,12 @@ int UtcDaliBubbleEmitterSetBlendMode(void)
 
   Image shapeImage = CreateSolidColorImage( application, Color::GREEN, 5, 5 );
   BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 150, Vector2( 5.f, 10.f ));
+  DALI_TEST_CHECK(emitter);
   Actor root = emitter.GetRootActor();
   Stage::GetCurrent().Add( root );
+  root.SetPosition( Vector3::ZERO );
+  root.SetParentOrigin( ParentOrigin::CENTER );
+  root.SetAnchorPoint( AnchorPoint::CENTER );
 
   TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
   Wait(application);
@@ -365,6 +374,9 @@ int UtcDaliBubbleEmitterRestore(void)
   BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 90, Vector2( 5.f, 10.f ));
   Actor root = emitter.GetRootActor();
   Stage::GetCurrent().Add( root );
+  root.SetPosition( Vector3::ZERO );
+  root.SetParentOrigin( ParentOrigin::CENTER );
+  root.SetAnchorPoint( AnchorPoint::CENTER );
 
   Actor bubbleMesh = root.GetChildAt( 0 );
   Renderer renderer = bubbleMesh.GetRendererAt( 0 );
@@ -407,5 +419,6 @@ int UtcDaliBubbleEmitterRestore(void)
 
   DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uStartEndPosition[0]", startEndPosValue ) );
   DALI_TEST_EQUALS( startEndPosValue,  Vector4::ZERO, TEST_LOCATION );
+
   END_TEST;
 }
index 5fa3d17..164ab9e 100644 (file)
@@ -21,6 +21,8 @@
 #include <dali-toolkit/devel-api/builder/builder.h>
 #include <dali/integration-api/events/touch-event-integ.h>
 
+#define STRINGIFY(A)#A
+
 using namespace Dali;
 using namespace Toolkit;
 
@@ -104,3 +106,1352 @@ int UtcDaliBuilderQuitSignal(void)
 
   END_TEST;
 }
+
+
+int UtcDaliBuilderAnimationP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+        "{"
+        "   \"constants\":"
+        "   {"
+        "     \"ALPHA_FUNCTION\":\"EASE_IN_OUT\""
+        "   },"
+        "   \"paths\":"
+        "   {"
+        "     \"path0\":"
+        "     {"
+        "       \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],"
+        "       \"curvature\":0.35"
+        "     }"
+        "   },"
+        "  \"animations\": {"
+        "    \"animate\": {"
+        "      \"loop\": true,"
+        "      \"end-action\": \"BAKE\","
+        "      \"disconnect-action\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"greeting\","
+        "        \"property\": \"position\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alpha-function\": \"{ALPHA_FUNCTION}\","
+        "        \"relative\": true,"
+        "        \"time-period\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"visible\","
+        "         \"alpha-function\": \"LINEAR\","
+        "         \"value\": true"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"size-width\","
+        "         \"alpha-function\": \"REVERSE\","
+        "         \"value\": 10.0"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_IN\","
+        "         \"value\": [10.0,20.0,30.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_OUT\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_IN_OUT\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_IN_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_OUT_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_IN_OUT_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"BOUNCE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"SIN\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alpha-function\": \"EASE_OUT_BACK\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       }"
+        "      ]"
+        "    },"
+        "    \"path-animation\": {"
+        "      \"duration\": 3.0,"
+        "      \"end-action\": \"DISCARD\","
+        "      \"disconnect-action\": \"BAKE_FINAL\","
+        "      \"properties\": [{"
+        "        \"actor\": \"greeting\","
+        "        \"path\":\"path0\","
+        "        \"forward\":[1,0,0],"
+        "        \"alpha-function\": \"EASE_IN_OUT\","
+        "        \"time-period\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }]"
+        "    }"
+        "  },"
+        "  \"stage\": [{"
+        "    \"name\": \"greeting\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\","
+        "    \"styles\": [\"basic-text\"],"
+        "    \"position\": [0, -120, 0],"
+        "    \"size\": [200, 200, 1],"
+        "    \"orientation\": [0, 0, 30],"
+        "    \"signals\": [{"
+        "      \"name\": \"touched\","
+        "      \"action\": \"play\","
+        "      \"animation\": \"animate\""
+        "    }]"
+        "  }]"
+        "}");
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+  Animation anim = builder.CreateAnimation("animate");
+
+  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 );
+
+  // trigger play
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  touchEvent.points.push_back( TouchPoint ( 0, TouchPoint::Down, 10.0f, 10.0f ) );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+
+  END_TEST;
+}
+
+int UtcDaliBuilderAnimationN(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+        "{"
+        "   \"constants\":"
+        "   {"
+        "     \"TEXT\": \"Touch Me\","
+        "     \"NAME\": \"greeting\" "
+        "   },"
+        "   \"paths\":"
+        "   {"
+        "     \"path0\":"
+        "     {"
+        "       \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],"
+        "       \"curvature\":0.35"
+        "     }"
+        "   },"
+        "  \"animations\": {"
+        "    \"animate\": {"
+        "      \"loop\": true,"
+        "      \"end-action\": \"BAKE\","
+        "      \"disconnect-action\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"{NAME}\","
+        "        \"property\": \"positioninvalid\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alpha-function\": \"EASE_IN_OUT\","
+        "        \"relative\": true,"
+        "        \"time-period\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }"
+        "      ]"
+        "    },"
+        "    \"animate2\": {"
+        "      \"loop\": true,"
+        "      \"end-action\": \"BAKE\","
+        "      \"disconnect-action\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"{NAME}\","
+        "        \"property\": \"positioninvalid\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alpha-function\": \"EGGS_OVER_EASY\","
+        "        \"relative\": true,"
+        "        \"time-period\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }"
+        "      ]"
+        "    },"
+        "    \"path-animation\": {"
+        "      \"duration\": 3.0,"
+        "      \"end-action\": \"DISCARD\","
+        "      \"disconnect-action\": \"BAKE_FINAL\","
+        "      \"properties\": [{"
+        "        \"actor\": \"greeting\","
+        "        \"path\":\"pathDoesntExist\","
+        "        \"forward\":[1,0,0],"
+        "        \"alpha-function\": \"EASE_IN_OUT\","
+        "        \"time-period\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }]"
+        "    }"
+        "  },"
+        "  \"stage\": [{"
+        "    \"name\": \"greeting\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\","
+        "    \"styles\": [\"basic-text\"],"
+        "    \"position\": [0, -120, 0],"
+        "    \"size\": [200, 200, 1],"
+        "    \"orientation\": [0, 0, 30],"
+        "    \"signals\": [{"
+        "      \"name\": \"touched\","
+        "      \"action\": \"play\","
+        "      \"animation\": \"animate\""
+        "    }]"
+        "  },"
+        "  {"
+        "    \"name\": \"greeting2\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\""
+        "  }]"
+        "}");
+
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+  Animation anim = builder.CreateAnimation("animate");
+
+  // 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);
+
+
+  END_TEST;
+
+}
+
+int UtcDaliBuilderConstantsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{"
+      "\"constants\":"
+      "{"
+      "  \"IMAGE_PATH\": \"apath\","
+      "  \"WIDTH\": 22.3,"
+      "  \"ANCHOR\": \"TOP_LEFT\","
+      "  \"PADDING\": [1,2,3,4]"
+      "},"
+      "\"stage\":"
+      "[{"
+      "  \"type\": \"ImageActor\","
+      "  \"name\": \"{NAME}\","
+      "  \"size\": [100,100,1],"
+      "  \"parent-origin\": \"TOP_LEFT\","
+      "  \"anchor-point\": \"{ANCHOR}\","
+      "  \"padding\": \"{PADDING}\","
+      "  \"image\": { \"filename\": \"dir/{IMAGE_PATH}\" },"
+      "  \"size-width\": \"{WIDTH}\","
+      "  \"signals\": [{"
+      "    \"name\": \"touched\","
+      "    \"action\": \"quit\""
+      "  }]"
+      "}]"
+      "}"
+  );
+
+  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;
+}
+
+int UtcDaliBuilderTemplatesAndStylesP(void)
+{
+  ToolkitTestApplication application;
+
+  // 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"
+      "  {\n"
+      "    \"color\": [1,0,0,1],\n"
+      "    \"actors\": {\n"
+      "      \"child-image\": {\n"
+      "        \"color\": [0,1,0,1]\n"
+      "      }\n"
+      "    }\n"
+      "  }\n"
+      "},\n"
+      "\"templates\":\n"
+      "{\n"
+      "  \"image-tree\": { \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"
+      "},\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;
+}
+
+int UtcDaliBuilderRenderTasksP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "\"render-tasks\":\n"
+      "{\n"
+      "  \"task0\": {\n"
+      "    \"source-actor\": \"image\",\n"
+      "    \"camera-actor\": \"camera\" \n"
+      "  }\n"
+      "},\n"
+      "\"stage\":\n"
+      "[\n"
+      "  { \n"
+      "    \"type\": \"CameraActor\",\n"
+      "    \"name\": \"image\"\n"
+      "  }, \n"
+      "  { \n"
+      "    \"type\": \"ImageActor\",\n"
+      "    \"name\": \"image\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"quit\"\n"
+      "    }],\n"
+      "    \"actors\": [\n"
+      "      {\n"
+      "        \"type\":\"ImageActor\",\n"
+      "        \"name\":\"child-image\" \n"
+      "      }\n"
+      "    ]\n"
+      "  }\n"
+      "]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  unsigned int count = Stage::GetCurrent().GetRenderTaskList().GetTaskCount();
+
+  // coverage
+  builder.CreateRenderTask( "task0" );
+
+  DALI_TEST_CHECK( count <
+                   Stage::GetCurrent().GetRenderTaskList().GetTaskCount() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderChildActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\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"
+      "    }],\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 ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  touchEvent.points.push_back( TouchPoint ( 0, TouchPoint::Down, 10.0f, 10.0f ) );
+  application.ProcessEvent( touchEvent );
+
+  // 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 UtcDaliBuilderSetPropertyActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\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"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"set\",\n"
+      "      \"actor\": \"sub-actor\",\n"
+      "      \"property\": \"visible\",\n"
+      "      \"value\": false\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  touchEvent.points.push_back( TouchPoint ( 0, TouchPoint::Down, 10.0f, 10.0f ) );
+  application.ProcessEvent( touchEvent );
+
+  // 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 UtcDaliBuilderGenericActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\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"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"hide\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  touchEvent.points.push_back( TouchPoint ( 0, TouchPoint::Down, 10.0f, 10.0f ) );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("actor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderPropertyNotificationP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\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"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touched\",\n"
+      "      \"action\": \"hide\"\n"
+      "    }],\n"
+      "    \"notifications\": [{\n"
+      "      \"property\": \"visible\",\n"
+      "      \"condition\": \"False\",\n"
+      "      \"action\": \"show\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  touchEvent.points.push_back( TouchPoint ( 0, TouchPoint::Down, 10.0f, 10.0f ) );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("actor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( actor.IsVisible() );
+
+  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 3223daa..722f0a8 100644 (file)
@@ -428,17 +428,15 @@ int UtcDaliControlBackgroundProperties(void)
 
   Property::Map imageMap;
   imageMap[ "filename" ] = "TestImage";
-  Property::Map map;
-  map[ "image" ] = imageMap;
-  control.SetProperty( Control::Property::BACKGROUND_IMAGE, map );
+  control.SetProperty( Control::Property::BACKGROUND_IMAGE, imageMap );
   DALI_TEST_CHECK( control.GetChildCount() > 0 );
   DALI_TEST_EQUALS( control.GetBackgroundColor(), Color::RED, TEST_LOCATION );
   DALI_TEST_EQUALS( control.GetProperty( Control::Property::BACKGROUND_COLOR ).Get< Vector4 >(), Color::RED, TEST_LOCATION );
 
   Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND_IMAGE );
-  DALI_TEST_CHECK( propValue.HasKey( "image" ) );
-  DALI_TEST_CHECK( propValue.GetValue( "image" ).HasKey( "filename" ) );
-  DALI_TEST_CHECK( propValue.GetValue( "image" ).GetValue( "filename" ).Get< std::string>() == "TestImage" );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( "filename" ) );
+  DALI_TEST_CHECK( resultMap->Find( "filename" )->Get< std::string>() == "TestImage" );
 
   Property::Map emptyMap;
   control.SetProperty( Control::Property::BACKGROUND_IMAGE, emptyMap );
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp
new file mode 100644 (file)
index 0000000..dc1e25a
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2014 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 <iostream>
+#include <stdlib.h>
+#include <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/effects-view/effects-view.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_effectsview_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_effectsview_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliEffectsViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  DALI_TEST_CHECK( !view );
+
+  view = EffectsView::New();
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( view );
+
+  EffectsView copy( view );
+  DALI_TEST_CHECK( copy == view );
+
+  EffectsView assign;
+  DALI_TEST_CHECK( !assign );
+  assign = view;
+  DALI_TEST_CHECK( assign == view );
+
+  // Self assignment
+  assign = assign;
+  DALI_TEST_CHECK( assign );
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle view = EffectsView::New();
+  DALI_TEST_CHECK( EffectsView::DownCast( view ) );
+
+  BaseHandle empty;
+  DALI_TEST_CHECK( ! EffectsView::DownCast( empty ) );
+
+  BaseHandle another = Actor::New();
+  DALI_TEST_CHECK( ! EffectsView::DownCast( another ) );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetGetTypeP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( view.GetType() == EffectsView::INVALID_TYPE );
+
+  view.SetType( EffectsView::DROP_SHADOW );
+  DALI_TEST_CHECK( view.GetType() == EffectsView::DROP_SHADOW );
+
+  view.SetType( EffectsView::EMBOSS );
+  DALI_TEST_CHECK( view.GetType() == EffectsView::EMBOSS );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetTypeN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetType( EffectsView::DROP_SHADOW );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetTypeN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    EffectsView::EffectType type = view.GetType();
+    (void) type;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewEnableP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  Stage stage = Stage::GetCurrent();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  view.Enable();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() > 1 );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewEnableN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.Enable();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewDisableP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  Stage stage = Stage::GetCurrent();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  view.Enable();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() > 1 );
+
+  view.Disable();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewDisableN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.Disable();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewRefreshP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  try
+  {
+    view.Refresh();
+    DALI_TEST_CHECK( true );
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( false ); // Should not get here!
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewRefreshN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.Refresh();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetPixelFormatP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  try
+  {
+    view.SetPixelFormat( Pixel::RGBA8888 );
+    DALI_TEST_CHECK( true );
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( false ); // Should not get here!
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetPixelFormatN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetPixelFormat( Pixel::RGBA8888 );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetGetOutputImage(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  FrameBufferImage image = FrameBufferImage::New();
+  DALI_TEST_CHECK( image );
+
+  view.SetOutputImage( image );
+  DALI_TEST_CHECK( view.GetOutputImage() == image );
+
+  // Replace with another image
+  FrameBufferImage image2 = FrameBufferImage::New();
+  DALI_TEST_CHECK( image2 );
+  view.SetOutputImage( image2 );
+  DALI_TEST_CHECK( view.GetOutputImage() == image2 );
+
+  // Remove output image
+  view.SetOutputImage( FrameBufferImage() );
+  DALI_TEST_CHECK( ! view.GetOutputImage() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetOutputImageN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetOutputImage( FrameBufferImage::New() );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetOutputImageN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    FrameBufferImage image = view.GetOutputImage();
+    (void)image;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectSizePropertyIndexP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( Property::INVALID_INDEX != view.GetEffectSizePropertyIndex() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectSizePropertyIndexN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Property::Index index = view.GetEffectSizePropertyIndex();
+    (void)index;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectStrengthPropertyIndexP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( Property::INVALID_INDEX != view.GetEffectStrengthPropertyIndex() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectStrengthPropertyIndexN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Property::Index index = view.GetEffectStrengthPropertyIndex();
+    (void)index;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectOffsetPropertyIndexP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( Property::INVALID_INDEX != view.GetEffectOffsetPropertyIndex() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectOffsetPropertyIndexN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Property::Index index = view.GetEffectOffsetPropertyIndex();
+    (void)index;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectColorPropertyIndexP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  DALI_TEST_CHECK( Property::INVALID_INDEX != view.GetEffectColorPropertyIndex() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetEffectColorPropertyIndexN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Property::Index index = view.GetEffectColorPropertyIndex();
+    (void)index;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetSetBackgroundColor(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  view.SetBackgroundColor( Color::RED );
+  DALI_TEST_CHECK( Color::RED == view.GetBackgroundColor() );
+
+  view.SetBackgroundColor( Color::YELLOW );
+  DALI_TEST_CHECK( Color::YELLOW == view.GetBackgroundColor() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetBackgroundColorN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetBackgroundColor( Color::RED );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetBackgroundColorN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Vector4 color = view.GetBackgroundColor();
+    (void)color;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetRefreshOnDemandP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New();
+  FrameBufferImage image = FrameBufferImage::New();
+  view.SetOutputImage( image );
+  view.Enable();
+
+  Stage stage = Stage::GetCurrent();
+  stage.Add( view );
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 2 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+
+  view.SetRefreshOnDemand( true );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ONCE );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 2 ).GetRefreshRate() == RenderTask::REFRESH_ONCE );
+
+  view.SetRefreshOnDemand( false );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 2 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetRefreshOnDemandN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetRefreshOnDemand( false );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSizeSet(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  {
+    EffectsView view = EffectsView::New();
+    view.SetSize( 200.0f, 200.0f, 200.0f );
+    stage.Add( view );
+    view.Enable();
+    application.SendNotification();
+    application.Render();
+    view.Disable();
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 200.0f ), TEST_LOCATION );
+  }
+
+  {
+    EffectsView view = EffectsView::New();
+    view.SetOutputImage( FrameBufferImage::New( 200, 200 ) );
+    view.SetType( EffectsView::EMBOSS );
+    view.SetSize( 200.0f, 200.0f, 200.0f );
+    stage.Add( view );
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 200.0f ), TEST_LOCATION );
+  }
+
+  {
+    EffectsView view = EffectsView::New();
+    view.SetType( EffectsView::DROP_SHADOW );
+    view.SetSize( 200.0f, 200.0f, 200.0f );
+    stage.Add( view );
+    application.SendNotification();
+    application.Render();
+
+    stage.Remove( view );
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 200.0f ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "EffectsView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  EffectsView view = EffectsView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
index 82527f4..b85524d 100644 (file)
@@ -40,16 +40,47 @@ void utc_dali_toolkit_item_view_cleanup(void)
 
 namespace
 {
+
 const unsigned int TOTAL_ITEM_NUMBER = 100;
 const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
 
+const int RENDER_FRAME_INTERVAL = 16;                     ///< Duration of each frame in ms. (at approx 60FPS)
+
 static bool gObjectCreatedCallBackCalled;
+static bool gOnLayoutActivatedCalled;                     ///< Whether the LayoutActivated signal was invoked.
 
 static void TestCallback(BaseHandle handle)
 {
   gObjectCreatedCallBackCalled = true;
 }
 
+static void OnLayoutActivated()
+{
+  gOnLayoutActivatedCalled = true;
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
 
 // Implementation of ItemFactory for providing actors to ItemView
 class TestItemFactory : public ItemFactory
@@ -771,3 +802,38 @@ int UtcDaliItemFactoryGetExtention(void)
   DALI_TEST_CHECK( factory.GetExtension() == NULL );
   END_TEST;
 }
+
+int UtcDaliItemViewLayoutActivatedSignalP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  Stage::GetCurrent().Add( view );
+
+  // Connect the layout activated signal
+  view.LayoutActivatedSignal().Connect( &OnLayoutActivated );
+
+  gOnLayoutActivatedCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.1f);
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  DALI_TEST_EQUALS( gOnLayoutActivatedCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp
new file mode 100644 (file)
index 0000000..1d6ba1b
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2014 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 <iostream>
+#include <stdlib.h>
+#include <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/magnifier/magnifier.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_magnifier_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_magnifier_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliMagnifierNew(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier magnifier;
+  DALI_TEST_CHECK( !magnifier );
+
+  magnifier = Magnifier::New();
+  DALI_TEST_CHECK( magnifier );
+
+  Stage::GetCurrent().Add( magnifier );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view = Magnifier::New();
+  DALI_TEST_CHECK( view );
+
+  Magnifier copy( view );
+  DALI_TEST_CHECK( copy == view );
+
+  Magnifier assign;
+  DALI_TEST_CHECK( !assign );
+  assign = view;
+  DALI_TEST_CHECK( assign == view );
+
+  // Self assignment
+  assign = assign;
+  DALI_TEST_CHECK( assign );
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle view = Magnifier::New();
+  DALI_TEST_CHECK( Magnifier::DownCast( view ) );
+
+  BaseHandle empty;
+  DALI_TEST_CHECK( ! Magnifier::DownCast( empty ) );
+
+  BaseHandle another = Actor::New();
+  DALI_TEST_CHECK( ! Magnifier::DownCast( another ) );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "Magnifier" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  Magnifier view = Magnifier::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSetSourceActorP(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_CHECK( renderTaskList.GetTaskCount() > 1 );
+
+  Actor actor = Actor::New();
+  stage.Add( actor );
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTask( 1 ).GetSourceActor() != actor );
+
+  view.SetSourceActor( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( stage.GetRenderTaskList().GetTask( 1 ).GetSourceActor(), actor, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSetSourceActorN(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view;
+
+  try
+  {
+    view.SetSourceActor( Actor::New() );
+    DALI_TEST_CHECK( false ); // should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierFrameVisibility(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::FRAME_VISIBILITY, false );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), false, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::FRAME_VISIBILITY, true );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierMagnificationFactor(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  float magnificationFactor( 200.0f );
+
+  DALI_TEST_CHECK( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >() != magnificationFactor );
+
+  view.SetProperty( Magnifier::Property::MAGNIFICATION_FACTOR, magnificationFactor );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), magnificationFactor, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), magnificationFactor, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::MAGNIFICATION_FACTOR, 1.0f );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), 1.0f, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSourcePosition(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position( 100.0f, 200.0f, 300.0f );
+
+  DALI_TEST_CHECK( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >() != position );
+
+  view.SetProperty( Magnifier::Property::SOURCE_POSITION, position );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >(), position, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::SOURCE_POSITION, Vector3::ONE );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >(), Vector3::ONE, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view = Magnifier::New();
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 200.0f );
+  view.SetSize( size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION );
+
+  END_TEST;
+}
index 8e6bffa..9c1e054 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <iostream>
 #include <stdlib.h>
+#include <sstream>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 
@@ -645,12 +646,14 @@ int UtcDaliTableViewSetGetProperty(void)
   Property::Map layoutRowsGet = tableView.GetProperty(TableView::Property::LAYOUT_ROWS).Get<Property::Map>();
 
   DALI_TEST_EQUALS( layoutRowsGet.GetKey(1).compare(layoutRows.GetKey(0)), 0, TEST_LOCATION );
-  DALI_TEST_CHECK( layoutRowsGet.GetValue(1).GetValue( "policy" ).Get<std::string>().compare(layoutRows.GetValue(0).GetValue( "policy" ).Get<std::string>()) == 0 );
-  DALI_TEST_EQUALS( layoutRowsGet.GetValue(1).GetValue( "value" ).Get<float>(), layoutRows.GetValue(0).GetValue( "value" ).Get<float>(), TEST_LOCATION );
+  Property::Map* childMap =layoutRowsGet.GetValue(1).GetMap();
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("fixed") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 30.f, TEST_LOCATION );
 
+  childMap =layoutRowsGet.GetValue(3).GetMap();
   DALI_TEST_CHECK( layoutRowsGet.GetKey(3).compare(layoutRows.GetKey(1)) == 0 );
-  DALI_TEST_CHECK( layoutRowsGet.GetValue(3).GetValue( "policy" ).Get<std::string>().compare(layoutRows.GetValue(1).GetValue( "policy" ).Get<std::string>()) == 0 );
-  DALI_TEST_EQUALS( layoutRowsGet.GetValue(3).GetValue( "value" ).Get<float>(), layoutRows.GetValue(1).GetValue( "value" ).Get<float>(), TEST_LOCATION );
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("relative") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 0.2f, TEST_LOCATION );
 
   // Test "layout-columns" property
   DALI_TEST_CHECK( tableView.GetPropertyIndex( PROPERTY_NAME_LAYOUT_COLUMNS ) == TableView::Property::LAYOUT_COLUMNS );
@@ -672,12 +675,13 @@ int UtcDaliTableViewSetGetProperty(void)
 
   Property::Map layoutColumnsGet = tableView.GetProperty(TableView::Property::LAYOUT_COLUMNS).Get<Property::Map>();
   DALI_TEST_CHECK( layoutColumnsGet.GetKey(2).compare(layoutColumns.GetKey(0)) == 0 );
-  DALI_TEST_CHECK( layoutColumnsGet.GetValue(2).GetValue( "policy" ).Get<std::string>().compare(layoutColumns.GetValue(0).GetValue( "policy" ).Get<std::string>()) == 0 );
-  DALI_TEST_EQUALS( layoutColumnsGet.GetValue(2).GetValue( "value" ).Get<float>(),layoutColumns.GetValue(0).GetValue( "value" ).Get<float>(), TEST_LOCATION );
-
+  childMap =layoutColumnsGet.GetValue(2).GetMap();
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("relative") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 0.2f, TEST_LOCATION );
+  childMap =layoutColumnsGet.GetValue(3).GetMap();
   DALI_TEST_CHECK( layoutColumnsGet.GetKey(3).compare(layoutColumns.GetKey(1)) == 0 );
-  DALI_TEST_CHECK( layoutColumnsGet.GetValue(3).GetValue( "policy" ).Get<std::string>().compare(layoutColumns.GetValue(1).GetValue( "policy" ).Get<std::string>()) == 0 );
-  DALI_TEST_EQUALS( layoutColumnsGet.GetValue(3).GetValue( "value" ).Get<float>(),layoutColumns.GetValue(1).GetValue( "value" ).Get<float>(), TEST_LOCATION );
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("fixed") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(),30.f, TEST_LOCATION );
 
   END_TEST;
 }
@@ -689,13 +693,14 @@ int UtcDaliTableViewCustomProperties(void)
 
   // Create a 10x10 table-view
   TableView tableView = TableView::New(10,10);
-  Constraint constraint = Constraint::New<Vector3>( tableView, Actor::Property::SIZE, Constraint100() );
-  constraint.Apply();
+  Stage::GetCurrent().Add( tableView );
+  tableView.SetSize( Dali::Vector2( 100.0f, 100.0f ) );
+
   DALI_TEST_CHECK( tableView );
 
   // Create a child actor with the custom properties
   Actor child1 = Actor::New();
-  child1.RegisterProperty( TableView::CELL_INDICES_PROPERTY_NAME, Vector2( 3, 4 ) );
+  child1.RegisterProperty( "cell-index", Vector2( 3, 4 ), Property::READ_WRITE );
   tableView.Add( child1 );
   // Check for actors at actual positions.
   DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(3,4)) == child1);
@@ -704,9 +709,9 @@ int UtcDaliTableViewCustomProperties(void)
   Actor child2 = Actor::New();
   float rowSpan = 3.f;
   float columnSpan = 2.f;
-  child2.RegisterProperty( TableView::CELL_INDICES_PROPERTY_NAME, Vector2( 6, 1 ) );
-  child2.RegisterProperty( TableView::ROW_SPAN_PROPERTY_NAME, rowSpan );
-  child2.RegisterProperty( TableView::COLUMN_SPAN_PROPERTY_NAME, columnSpan );
+  child2.RegisterProperty( "cell-index", Vector2( 6, 1 ), Property::READ_WRITE );
+  child2.RegisterProperty( "row-span", rowSpan, Property::READ_WRITE );
+  child2.RegisterProperty( "column-span", columnSpan, Property::READ_WRITE );
   tableView.Add( child2 );
   // Check for actors at actual positions.
   for( int i=0; i<rowSpan; i++ )
@@ -717,5 +722,196 @@ int UtcDaliTableViewCustomProperties(void)
     }
   }
 
+  // Create a third child actor with the cell alignment properties
+  Actor child3 = Actor::New();
+  child3.SetSize( 5.f,5.f );
+  child3.RegisterProperty( "cell-horizontal-alignment", "center", Property::READ_WRITE );
+  child3.RegisterProperty( "cell-vertical-alignment", "bottom", Property::READ_WRITE );
+  tableView.Add( child3 );
+
+  // store the actor in the first available cell
+  DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(0,0)) == child3)
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( child3.GetCurrentAnchorPoint(), AnchorPoint::TOP_LEFT, TEST_LOCATION );
+  DALI_TEST_EQUALS( child3.GetCurrentParentOrigin(), ParentOrigin::TOP_LEFT, TEST_LOCATION );
+  DALI_TEST_EQUALS( child3.GetCurrentPosition(), Vector3(2.5f, 5.0f, 0.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewGetChildAtN(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+
+  Actor actor = tableView.GetChildAt( TableView::CellPosition( 200, 200 ) );
+  DALI_TEST_CHECK( !actor );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewAddChildN(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 ) ) );
+  DALI_TEST_CHECK( ! tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 ) ) );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewInsertRowAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.InsertRow(0);
+
+  DALI_TEST_CHECK( tableView.GetRows() == 11 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewDeleteRowAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.DeleteRow(0);
+
+  DALI_TEST_CHECK( tableView.GetRows() == 9 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewInsertColumnAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.InsertColumn(0);
+
+  DALI_TEST_CHECK( tableView.GetColumns() == 11 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewDeleteColumnAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.DeleteColumn(0);
+
+  DALI_TEST_CHECK( tableView.GetColumns() == 9 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "TableView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  TableView view = TableView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewKeyboardFocus(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(4,4);
+  tableView.SetKeyboardFocusable( true );
+  tableView.SetName( "TableView");
+
+  for ( int row = 0; row < 4; ++row )
+  {
+    for ( int col = 0; col < 4; ++col )
+    {
+      Control control = Control::New();
+      std::ostringstream str;
+      str << row << "-" << col;
+      control.SetName( str.str() );
+      control.SetKeyboardFocusable( true );
+      tableView.AddChild( control, TableView::CellPosition( row, col ) );
+    }
+  }
+
+  Stage::GetCurrent().Add( tableView );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor firstFocusActor = Toolkit::Internal::GetImplementation( tableView ).GetNextKeyboardFocusableActor( Actor(), Control::KeyboardFocus::RIGHT, true );
+  DALI_TEST_CHECK( firstFocusActor );
+  DALI_TEST_CHECK( firstFocusActor.GetName() == "0-0" );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  manager.SetFocusGroupLoop( true );
+  manager.SetCurrentFocusActor( firstFocusActor );
+
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-3" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-0" );
+
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-3" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-3" );
+
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
   END_TEST;
 }
index d19b3a1..2838251 100644 (file)
@@ -18,6 +18,7 @@
 #include <iostream>
 #include <stdlib.h>
 #include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/tap-gesture-event.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/styling/style-manager.h>
@@ -38,22 +39,49 @@ void dali_textfield_cleanup(void)
 namespace
 {
 
-const char* const PROPERTY_NAME_RENDERING_BACKEND       = "rendering-backend";
-const char* const PROPERTY_NAME_PLACEHOLDER_TEXT        = "placeholder-text";
-const char* const PROPERTY_NAME_TEXT                    = "text";
-const char* const PROPERTY_NAME_FONT_FAMILY             = "font-family";
-const char* const PROPERTY_NAME_FONT_STYLE              = "font-style";
-const char* const PROPERTY_NAME_POINT_SIZE              = "point-size";
-const char* const PROPERTY_NAME_EXCEED_POLICY           = "exceed-policy";
-const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR    = "primary-cursor-color";
-const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR  = "secondary-cursor-color";
-const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK     = "enable-cursor-blink";
-const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL   = "cursor-blink-interval";
-const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION   = "cursor-blink-duration";
-const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE       = "grab-handle-image";
-const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decoration-bounding-box";
-const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT    = "horizontal-alignment";
-const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT      = "vertical-alignment";
+const char* const PROPERTY_NAME_RENDERING_BACKEND                    = "rendering-backend";
+const char* const PROPERTY_NAME_TEXT                                 = "text";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT                     = "placeholder-text";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_FOCUSED             = "placeholder-text-focused";
+const char* const PROPERTY_NAME_FONT_FAMILY                          = "font-family";
+const char* const PROPERTY_NAME_FONT_STYLE                           = "font-style";
+const char* const PROPERTY_NAME_POINT_SIZE                           = "point-size";
+const char* const PROPERTY_NAME_MAX_LENGTH                           = "max-length";
+const char* const PROPERTY_NAME_EXCEED_POLICY                        = "exceed-policy";
+const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT                 = "horizontal-alignment";
+const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT                   = "vertical-alignment";
+const char* const PROPERTY_NAME_TEXT_COLOR                           = "text-color";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR               = "placeholder-text-color";
+const char* const PROPERTY_NAME_SHADOW_OFFSET                        = "shadow-offset";
+const char* const PROPERTY_NAME_SHADOW_COLOR                         = "shadow-color";
+const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR                 = "primary-cursor-color";
+const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR               = "secondary-cursor-color";
+const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK                  = "enable-cursor-blink";
+const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL                = "cursor-blink-interval";
+const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION                = "cursor-blink-duration";
+const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE                    = "grab-handle-image";
+const char* const PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE            = "grab-handle-pressed-image";
+const char* const PROPERTY_NAME_SCROLL_THRESHOLD                     = "scroll-threshold";
+const char* const PROPERTY_NAME_SCROLL_SPEED                         = "scroll-speed";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT          = "selection-handle-image-left";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT         = "selection-handle-image-right";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT  = "selection-handle-pressed-image-left";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = "selection-handle-pressed-image-right";
+const char* const PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR            = "selection-highlight-color";
+const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX              = "decoration-bounding-box";
+const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS                = "input-method-settings";
+
+const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+
+const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
+const Dali::Vector4 LIGHT_BLUE( (0xb2 / 255.0f), (0xeb / 255.0f), (0xf2 / 255.0f), 0.5f ); // The text highlight color.
+
+const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
+const float TO_MILLISECONDS = 1000.f;
+const float TO_SECONDS = 1.f / TO_MILLISECONDS;
+
+const float SCROLL_THRESHOLD = 10.f;
+const float SCROLL_SPEED = 300.f;
 
 static bool gTextChangedCallBackCalled;
 static bool gMaxCharactersCallBackCalled;
@@ -72,6 +100,38 @@ static void TestMaxLengthReachedCallback( TextField control )
   gMaxCharactersCallBackCalled = true;
 }
 
+// Generate a TapGestureEvent to send to Core.
+Integration::TapGestureEvent GenerateTap(
+    Gesture::State state,
+    unsigned int numberOfTaps,
+    unsigned int numberOfTouches,
+    Vector2 point)
+{
+  Integration::TapGestureEvent tap( state );
+
+  tap.numberOfTaps = numberOfTaps;
+  tap.numberOfTouches = numberOfTouches;
+  tap.point = point;
+
+  return tap;
+}
+
+// Generate a KeyEvent to send to Core.
+Integration::KeyEvent GenerateKey( const std::string& keyName,
+                                   const std::string& keyString,
+                                   int keyCode,
+                                   int keyModifier,
+                                   unsigned long timeStamp,
+                                   const Integration::KeyEvent::State& keyState )
+{
+  return Integration::KeyEvent( keyName,
+                                keyString,
+                                keyCode,
+                                keyModifier,
+                                timeStamp,
+                                keyState );
+}
+
 } // namespace
 
 int UtcDaliToolkitTextFieldConstructorP(void)
@@ -155,33 +215,6 @@ int UtcDaliTextFieldNewP(void)
   END_TEST;
 }
 
-int UtcDaliTextFieldGetPropertyN(void)
-{
-  ToolkitTestApplication application;
-  tet_infoline(" UtcDaliToolkitTextFieldGetPropertyN");
-  TextField field = TextField::New();
-  DALI_TEST_CHECK( field );
-
-  bool assert = false;
-  try
-  {
-    Property::Value value = field.GetProperty<bool>( 0 );
-  }
-  catch ( ... )
-  {
-    assert = true;
-  }
-  if ( assert )
-  {
-    tet_result(TET_PASS);
-  }
-  else
-  {
-    tet_result(TET_FAIL);
-  }
-  END_TEST;
-}
-
 // Positive test case for a method
 int UtcDaliTextFieldGetPropertyP(void)
 {
@@ -192,21 +225,36 @@ int UtcDaliTextFieldGetPropertyP(void)
 
   // Check Property Indices are correct
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_RENDERING_BACKEND ) == TextField::Property::RENDERING_BACKEND );
-  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT ) == TextField::Property::PLACEHOLDER_TEXT );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_TEXT ) == TextField::Property::TEXT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT ) == TextField::Property::PLACEHOLDER_TEXT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_FOCUSED ) == TextField::Property::PLACEHOLDER_TEXT_FOCUSED );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_FONT_FAMILY ) == TextField::Property::FONT_FAMILY );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_FONT_STYLE ) == TextField::Property::FONT_STYLE );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_POINT_SIZE ) == TextField::Property::POINT_SIZE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_MAX_LENGTH ) == TextField::Property::MAX_LENGTH );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_EXCEED_POLICY ) == TextField::Property::EXCEED_POLICY );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextField::Property::HORIZONTAL_ALIGNMENT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_VERTICAL_ALIGNMENT ) == TextField::Property::VERTICAL_ALIGNMENT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_TEXT_COLOR ) == TextField::Property::TEXT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR ) == TextField::Property::PLACEHOLDER_TEXT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SHADOW_OFFSET ) == TextField::Property::SHADOW_OFFSET );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SHADOW_COLOR ) == TextField::Property::SHADOW_COLOR );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PRIMARY_CURSOR_COLOR ) == TextField::Property::PRIMARY_CURSOR_COLOR );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SECONDARY_CURSOR_COLOR ) == TextField::Property::SECONDARY_CURSOR_COLOR );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_CURSOR_BLINK ) == TextField::Property::ENABLE_CURSOR_BLINK );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_INTERVAL ) == TextField::Property::CURSOR_BLINK_INTERVAL );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_DURATION ) == TextField::Property::CURSOR_BLINK_DURATION );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_IMAGE ) == TextField::Property::GRAB_HANDLE_IMAGE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE ) == TextField::Property::GRAB_HANDLE_PRESSED_IMAGE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SCROLL_THRESHOLD ) == TextField::Property::SCROLL_THRESHOLD );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SCROLL_SPEED ) == TextField::Property::SCROLL_SPEED );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT ) == TextField::Property::SELECTION_HANDLE_IMAGE_LEFT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT ) == TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT ) == TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ) == TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR ) == TextField::Property::SELECTION_HIGHLIGHT_COLOR );
   DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_DECORATION_BOUNDING_BOX ) == TextField::Property::DECORATION_BOUNDING_BOX );
-  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextField::Property::HORIZONTAL_ALIGNMENT );
-  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_VERTICAL_ALIGNMENT ) == TextField::Property::VERTICAL_ALIGNMENT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_METHOD_SETTINGS ) == TextField::Property::INPUT_METHOD_SETTINGS );
   END_TEST;
 }
 
@@ -218,76 +266,123 @@ int UtcDaliTextFieldSetPropertyP(void)
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
-  // Check exceed policy
-  field.SetProperty( TextField::Property::EXCEED_POLICY, TextField::EXCEED_POLICY_CLIP );
+  // Check defaults.
+  DALI_TEST_EQUALS( field.GetProperty<unsigned int>( TextField::Property::RENDERING_BACKEND ), DEFAULT_RENDERING_BACKEND, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT_FOCUSED ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::FONT_FAMILY ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::FONT_STYLE ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::POINT_SIZE ), 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::MAX_LENGTH ), 50u, TEST_LOCATION );
   DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::EXCEED_POLICY ), TextField::EXCEED_POLICY_CLIP, TEST_LOCATION );
-
-  // Check cursor properties
-  field.SetProperty( TextField::Property::ENABLE_CURSOR_BLINK, true );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::HORIZONTAL_ALIGNMENT ), "BEGIN", TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::VERTICAL_ALIGNMENT ), "TOP", TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::TEXT_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector2>( TextField::Property::SHADOW_OFFSET ), Vector2::ZERO, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PLACEHOLDER_TEXT_COLOR ), PLACEHOLDER_TEXT_COLOR, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SHADOW_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PRIMARY_CURSOR_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SECONDARY_CURSOR_COLOR ), Color::BLACK, TEST_LOCATION );
   DALI_TEST_EQUALS( field.GetProperty<bool>( TextField::Property::ENABLE_CURSOR_BLINK ), true, TEST_LOCATION );
-  field.SetProperty( TextField::Property::PRIMARY_CURSOR_COLOR, Color::RED );
-  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PRIMARY_CURSOR_COLOR ), Color::RED, TEST_LOCATION );
-  field.SetProperty( TextField::Property::SECONDARY_CURSOR_COLOR, Color::BLUE );
-  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SECONDARY_CURSOR_COLOR ), Color::BLUE, TEST_LOCATION );
-  field.SetProperty( TextField::Property::CURSOR_BLINK_DURATION, 10.0f );
-  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_DURATION ), 10.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_INTERVAL ), CURSOR_BLINK_INTERVAL * TO_SECONDS, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_DURATION ), 0.f, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_THRESHOLD ), SCROLL_THRESHOLD, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_SPEED ), SCROLL_SPEED, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SELECTION_HIGHLIGHT_COLOR ), LIGHT_BLUE, TEST_LOCATION );
 
-  // Blink interval
-  field.SetProperty( TextField::Property::CURSOR_BLINK_INTERVAL, 1.0f );
-  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_INTERVAL ), 1.0f, TEST_LOCATION );
+  // Check the render backend property.
+  field.SetProperty( TextField::Property::RENDERING_BACKEND, Text::RENDERING_BASIC );
+  DALI_TEST_EQUALS( field.GetProperty<unsigned int>( TextField::Property::RENDERING_BACKEND ), Text::RENDERING_BASIC, TEST_LOCATION );
 
-  // Decoration bounding box
-  field.SetProperty( TextField::Property::DECORATION_BOUNDING_BOX, Rect<int>( 0, 0, 1, 1 ) );
-  DALI_TEST_EQUALS( field.GetProperty<Rect <int > >( TextField::Property::DECORATION_BOUNDING_BOX ), Rect<int>( 0, 0, 1, 1 ), TEST_LOCATION );
-
-  // Check that the Alignment properties can be correctly set
-  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "BEGIN" );
-  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::HORIZONTAL_ALIGNMENT ), "BEGIN", TEST_LOCATION );
-  field.SetProperty( TextField::Property::VERTICAL_ALIGNMENT, "CENTER" );
-  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::VERTICAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
-
-  // Set text
+  // Check text property.
   field.SetProperty( TextField::Property::TEXT, "Setting Text" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
+
+  // Check placeholder text properties.
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Setting Placeholder Text" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT ), std::string("Setting Placeholder Text"), TEST_LOCATION );
 
-  // Set placeholder text (currently not implemented)
-  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Setting Text" );
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_FOCUSED, "Setting Placeholder Text Focused" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT_FOCUSED ), std::string("Setting Placeholder Text Focused"), TEST_LOCATION );
 
-  // Set Grab Handle image
-  field.SetProperty( TextField::Property::GRAB_HANDLE_IMAGE, "" );
+  // Check font properties.
+  field.SetProperty( TextField::Property::FONT_FAMILY, "Setting font family" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
+  field.SetProperty( TextField::Property::FONT_STYLE, "Setting font style" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::FONT_STYLE ), std::string("Setting font style"), TEST_LOCATION );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
 
   // Check that the MAX_LENGTH property can be correctly set
   const int maxNumberOfCharacters = 20;
   field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
   DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::MAX_LENGTH ), maxNumberOfCharacters, TEST_LOCATION );
 
-  END_TEST;
-}
+  // Check exceed policy
+  // Set a different exceed policy is not implemented.
 
-// Negative test case for a method
-int UtcDaliTextFieldSetPropertyN(void)
-{
-  ToolkitTestApplication application;
-  tet_infoline(" UtcDaliToolkitTextFieldSetPropertyN");
-  TextField field = TextField::New();
-  DALI_TEST_CHECK( field );
+  // Check that the Alignment properties can be correctly set
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "END" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::HORIZONTAL_ALIGNMENT ), "END", TEST_LOCATION );
+  field.SetProperty( TextField::Property::VERTICAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::VERTICAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+
+  // Check text's color property
+  field.SetProperty( TextField::Property::TEXT_COLOR, Color::WHITE );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::TEXT_COLOR ), Color::WHITE, TEST_LOCATION );
+
+  // Check placeholder text's color property.
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_COLOR, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PLACEHOLDER_TEXT_COLOR ), Color::RED, TEST_LOCATION );
+
+  // Check shadow properties.
+  field.SetProperty( TextField::Property::SHADOW_OFFSET, Vector2( 1.f, 1.f ) );
+  DALI_TEST_EQUALS( field.GetProperty<Vector2>( TextField::Property::SHADOW_OFFSET ), Vector2( 1.f, 1.f ), TEST_LOCATION );
+  field.SetProperty( TextField::Property::SHADOW_COLOR, Color::GREEN );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SHADOW_COLOR ), Color::GREEN, TEST_LOCATION );
+
+  // Check cursor properties
+  field.SetProperty( TextField::Property::PRIMARY_CURSOR_COLOR, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PRIMARY_CURSOR_COLOR ), Color::RED, TEST_LOCATION );
+  field.SetProperty( TextField::Property::SECONDARY_CURSOR_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SECONDARY_CURSOR_COLOR ), Color::BLUE, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::ENABLE_CURSOR_BLINK, false );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( TextField::Property::ENABLE_CURSOR_BLINK ), false, TEST_LOCATION );
+  field.SetProperty( TextField::Property::CURSOR_BLINK_INTERVAL, 1.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_INTERVAL ), 1.f, TEST_LOCATION );
+  field.SetProperty( TextField::Property::CURSOR_BLINK_DURATION, 10.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_DURATION ), 10.f, TEST_LOCATION );
+
+  // Check scroll properties.
+  field.SetProperty( TextField::Property::SCROLL_THRESHOLD, 1.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_THRESHOLD ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  field.SetProperty( TextField::Property::SCROLL_SPEED, 100.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_SPEED ), 100.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check handle images
+  field.SetProperty( TextField::Property::GRAB_HANDLE_IMAGE, "image1" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::GRAB_HANDLE_IMAGE ), "image1", TEST_LOCATION );
+  field.SetProperty( TextField::Property::GRAB_HANDLE_PRESSED_IMAGE, "image2" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::GRAB_HANDLE_PRESSED_IMAGE ), "image2", TEST_LOCATION );
+  field.SetProperty( TextField::Property::SELECTION_HANDLE_IMAGE_LEFT, "image3" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::SELECTION_HANDLE_IMAGE_LEFT ), "image3", TEST_LOCATION );
+  field.SetProperty( TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT, "image4" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT ), "image4", TEST_LOCATION );
+  field.SetProperty( TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, "image5" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT ), "image5", TEST_LOCATION );
+  field.SetProperty( TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, "image6" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ), "image6", TEST_LOCATION );
+
+  // Check the highlight color
+  field.SetProperty( TextField::Property::SELECTION_HIGHLIGHT_COLOR, Color::GREEN );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SELECTION_HIGHLIGHT_COLOR ), Color::GREEN, TEST_LOCATION );
+
+  // Decoration bounding box
+  field.SetProperty( TextField::Property::DECORATION_BOUNDING_BOX, Rect<int>( 0, 0, 1, 1 ) );
+  DALI_TEST_EQUALS( field.GetProperty<Rect <int > >( TextField::Property::DECORATION_BOUNDING_BOX ), Rect<int>( 0, 0, 1, 1 ), TEST_LOCATION );
 
-  bool assert = false;
-  try
-  {
-    field.SetProperty( 0, true );
-  }
-  catch ( ... )
-  {
-    assert = true;
-  }
-  if ( assert )
-  {
-    tet_result(TET_PASS);
-  }
-  else
-  {
-    tet_result(TET_FAIL);
-  }
   END_TEST;
 }
 
@@ -301,6 +396,10 @@ int utcDaliTextFieldBasicRenderP(void)
 
   field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "BEGIN" );
 
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( field );
+
   try
   {
     // Render some text with the basic backend
@@ -326,6 +425,11 @@ int utcDaliTextFieldAtlasRenderP(void)
   DALI_TEST_CHECK( field );
 
   field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( field );
+
   try
   {
     // Render some text with the shared atlas backend
@@ -348,7 +452,7 @@ int utcDaliTextFieldTextChangedP(void)
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
-  Stage::GetCurrent().Add(field);
+  Stage::GetCurrent().Add( field );
 
   field.TextChangedSignal().Connect(&TestTextChangedCallback);
 
@@ -360,16 +464,8 @@ int utcDaliTextFieldTextChangedP(void)
 
   field.SetKeyInputFocus();
 
-  Dali::Integration::KeyEvent keyevent;
-  keyevent.keyName = "D";
-  keyevent.keyString = "D";
-  keyevent.keyCode = 0;
-  keyevent.keyModifier = 0;
-  keyevent.time = 0;
-  keyevent.state = Integration::KeyEvent::Down;
-
   gTextChangedCallBackCalled = false;
-  application.ProcessEvent( keyevent );
+  application.ProcessEvent( GenerateKey( "D", "D", 0, 0, 0, Integration::KeyEvent::Down ) );
   DALI_TEST_CHECK( gTextChangedCallBackCalled );
 
   END_TEST;
@@ -383,13 +479,13 @@ int utcDaliTextFieldTextChangedN(void)
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
-  Stage::GetCurrent().Add(field);
+  Stage::GetCurrent().Add( field );
 
   field.TextChangedSignal().Connect(&TestTextChangedCallback);
 
   gTextChangedCallBackCalled = false;
   field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT
-  DALI_TEST_CHECK( ! gTextChangedCallBackCalled );
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
 
   END_TEST;
 }
@@ -402,7 +498,7 @@ int utcDaliTextFieldMaxCharactersReachedP(void)
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
-  Stage::GetCurrent().Add(field);
+  Stage::GetCurrent().Add( field );
 
   const int maxNumberOfCharacters = 1;
   field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
@@ -412,17 +508,8 @@ int utcDaliTextFieldMaxCharactersReachedP(void)
   gMaxCharactersCallBackCalled = false;
   field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback);
 
-  Dali::Integration::KeyEvent keyevent;
-  keyevent.keyName = "a";
-  keyevent.keyString = "a";
-  keyevent.keyCode = 0;
-  keyevent.keyModifier = 0;
-  keyevent.time = 0;
-  keyevent.state = Integration::KeyEvent::Down;
-
-  application.ProcessEvent( keyevent );
-
-  application.ProcessEvent( keyevent );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
 
   DALI_TEST_CHECK( gMaxCharactersCallBackCalled );
 
@@ -437,7 +524,7 @@ int utcDaliTextFieldMaxCharactersReachedN(void)
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
-  Stage::GetCurrent().Add(field);
+  Stage::GetCurrent().Add( field );
 
   const int maxNumberOfCharacters = 3;
   field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
@@ -447,18 +534,294 @@ int utcDaliTextFieldMaxCharactersReachedN(void)
   gMaxCharactersCallBackCalled = false;
   field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback);
 
-  Dali::Integration::KeyEvent keyevent;
-  keyevent.keyName = "a";
-  keyevent.keyString = "a";
-  keyevent.keyCode = 0;
-  keyevent.keyModifier = 0;
-  keyevent.time = 0;
-  keyevent.state = Integration::KeyEvent::Down;
-
-  application.ProcessEvent( keyevent );
-  application.ProcessEvent( keyevent );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
 
   DALI_TEST_CHECK( !gMaxCharactersCallBackCalled );
 
   END_TEST;
 }
+
+int utcDaliTextFieldEvent01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent01");
+
+  // Creates a tap event. After creating a tap event the text field should
+  // have the focus and add text with key events should be possible.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a key event but as the text field has not the focus it should do nothing.
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string(""), TEST_LOCATION );
+
+  // Create a tap event to touch the text field.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Now the text field has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  // Create a second text field and send key events to it.
+  TextField field2 = TextField::New();
+
+  field2.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field2.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  field2.SetSize( 100.f, 100.f );
+  field2.SetPosition( 100.f, 100.f );
+
+  Stage::GetCurrent().Add( field2 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event on the second text field.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 125.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 125.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The second text field has the focus. It should handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check the text has been added to the second text field.
+  DALI_TEST_EQUALS( field2.GetProperty<std::string>( TextField::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent02");
+
+  // Checks if the right number of actors are created.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check there are the expected number of children ( active layer, offscreen root actor, and the offscreen image actor
+  DALI_TEST_EQUALS( field.GetChildCount(), 3u, TEST_LOCATION );
+
+  Actor layer = field.GetChildAt( 0u );
+  DALI_TEST_CHECK( layer.IsLayer() );
+
+  Actor offscreenRoot = field.GetChildAt( 1u );
+  DALI_TEST_CHECK( offscreenRoot.IsLayer() );
+  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor.
+
+  Actor offscreenImage = field.GetChildAt( 2u );
+  ImageActor imageActor = ImageActor::DownCast( offscreenImage );
+  DALI_TEST_CHECK( imageActor );
+
+  // Create a tap event to touch the text field.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 150.0f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor.
+
+  // Now the text field has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "a", "a", 0, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Checks the cursor and the renderer have been created.
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 2u, TEST_LOCATION ); // The camera actor and the renderer
+
+  ImageActor cursor = ImageActor::DownCast( layer.GetChildAt( 0u ) );
+  DALI_TEST_CHECK( cursor );
+
+  CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) );
+  DALI_TEST_CHECK( camera );
+
+  RenderableActor renderer = RenderableActor::DownCast( offscreenRoot.GetChildAt( 1u ) );
+  DALI_TEST_CHECK( renderer );
+
+  // Move the cursor and check the position changes.
+  Vector3 position1 = cursor.GetCurrentPosition();
+
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position2 = cursor.GetCurrentPosition();
+
+  DALI_TEST_CHECK( position2.x < position1.x );
+
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position3 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position1, position3, TEST_LOCATION ); // Should be in the same position1.
+
+  // Send some taps and check the cursor positions.
+
+  // Try to tap at the beginning.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position1.
+  Vector3 position4 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2.
+
+  // Try to tap at the end.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 13.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 13.0f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position1.
+  Vector3 position5 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position1, position5, TEST_LOCATION ); // Should be in the same position1.
+
+  // Remove some text.
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) );
+  application.ProcessEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position2.
+  Vector3 position6 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( Vector3( 0.f, position2.y, position2.z ), position6, TEST_LOCATION ); // TODO Should be in the same position2.
+
+  // Should not be renderer.
+  DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor only.
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent03");
+
+  // Checks if the highlight actor is created.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetSize( 30.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 3.f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 3.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 3.f, 25.0f ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The offscreen root actor should have three actors: the camera, a renderer and the highlight actor.
+  Actor offscreenRoot = field.GetChildAt( 1u );
+  DALI_TEST_CHECK( offscreenRoot.IsLayer() );
+
+  CameraActor camera = CameraActor::DownCast( offscreenRoot.GetChildAt( 0u ) );
+  DALI_TEST_CHECK( camera );
+
+  RenderableActor renderer = RenderableActor::DownCast( offscreenRoot.GetChildAt( 1u ) );
+  DALI_TEST_CHECK( renderer );
+
+  MeshActor highlight = MeshActor::DownCast( offscreenRoot.GetChildAt( 2u ) );
+  DALI_TEST_CHECK( highlight );
+
+  END_TEST;
+}
index c0e4bec..dd5d091 100644 (file)
@@ -51,6 +51,8 @@ const char* const PROPERTY_NAME_UNDERLINE_ENABLED = "underline-enabled";
 const char* const PROPERTY_NAME_UNDERLINE_COLOR = "underline-color";
 const char* const PROPERTY_NAME_UNDERLINE_HEIGHT = "underline-height";
 
+const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+
 } // namespace
 
 int UtcDaliToolkitTextLabelConstructorP(void)
@@ -125,33 +127,6 @@ int UtcDaliToolkitTextLabelAssignmentOperatorP(void)
   END_TEST;
 }
 
-int UtcDaliToolkitTextLabelGetPropertyN(void)
-{
-  ToolkitTestApplication application;
-  tet_infoline(" UtcDaliToolkitTextLabelGetPropertyN");
-  TextLabel label = TextLabel::New("Test Text");
-  DALI_TEST_CHECK( label );
-
-  bool assert = false;
-  try
-  {
-    Property::Value value = label.GetProperty<bool>( 0 );
-  }
-  catch ( ... )
-  {
-    assert = true;
-  }
-  if ( assert )
-  {
-    tet_result(TET_PASS);
-  }
-  else
-  {
-    tet_result(TET_FAIL);
-  }
-  END_TEST;
-}
-
 // Positive test case for a method
 int UtcDaliToolkitTextLabelGetPropertyP(void)
 {
@@ -176,40 +151,6 @@ int UtcDaliToolkitTextLabelGetPropertyP(void)
   DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_UNDERLINE_COLOR ) == TextLabel::Property::UNDERLINE_COLOR );
   DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_UNDERLINE_HEIGHT) == TextLabel::Property::UNDERLINE_HEIGHT );
 
-  // Check label defaults are correct
-  DALI_TEST_EQUALS( label.GetProperty<int>( TextLabel::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION );
-  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ), Color::BLACK, TEST_LOCATION );
-  DALI_TEST_EQUALS( label.GetProperty<Vector2>( TextLabel::Property::SHADOW_OFFSET ), Vector2::ZERO, TEST_LOCATION );
-  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::SHADOW_COLOR ), Color::BLACK, TEST_LOCATION );
-  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::UNDERLINE_ENABLED ), false, TEST_LOCATION );
-  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::UNDERLINE_HEIGHT ), 0.0f, TEST_LOCATION );
-  END_TEST;
-}
-
-int UtcDaliToolkitTextLabelSetPropertyN(void)
-{
-  ToolkitTestApplication application;
-  tet_infoline(" UtcDaliToolkitTextLabelSetPropertyN");
-  TextLabel label = TextLabel::New("Test Text");
-  DALI_TEST_CHECK( label );
-
-  bool assert = false;
-  try
-  {
-    label.SetProperty( 0, true );
-  }
-  catch ( ... )
-  {
-    assert = true;
-  }
-  if ( assert )
-  {
-    tet_result(TET_PASS);
-  }
-  else
-  {
-    tet_result(TET_FAIL);
-  }
   END_TEST;
 }
 
@@ -217,18 +158,55 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
 {
   ToolkitTestApplication application;
   tet_infoline(" UtcDaliToolkitTextLabelSetPropertyP");
-  TextLabel label = TextLabel::New("Test Text");
+  TextLabel label = TextLabel::New();
   DALI_TEST_CHECK( label );
 
+  // Check defaults
+  DALI_TEST_EQUALS( label.GetProperty<unsigned int>( TextLabel::Property::RENDERING_BACKEND ), DEFAULT_RENDERING_BACKEND, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::FONT_FAMILY ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::FONT_STYLE ), std::string(""), TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::POINT_SIZE ), 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::MULTI_LINE ), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::HORIZONTAL_ALIGNMENT ), "BEGIN", TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::VERTICAL_ALIGNMENT ), "TOP", TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<Vector2>( TextLabel::Property::SHADOW_OFFSET ), Vector2::ZERO, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::SHADOW_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::UNDERLINE_ENABLED ), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::UNDERLINE_COLOR ), Color::BLACK, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::UNDERLINE_HEIGHT ), 0.0f, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Text::RENDERING_BASIC );
+  DALI_TEST_EQUALS( label.GetProperty<unsigned int>( TextLabel::Property::RENDERING_BACKEND ), Text::RENDERING_BASIC, TEST_LOCATION );
+
   // Check that text can be correctly reset
   label.SetProperty( TextLabel::Property::TEXT, "Setting Text" );
-  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), "Setting Text", TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
+
+  // Check font properties.
+  label.SetProperty( TextLabel::Property::FONT_FAMILY, "Setting font family" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::FONT_STYLE, "Setting font style" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::FONT_STYLE ), std::string("Setting font style"), TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 10.f );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Toggle multi-line
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::MULTI_LINE ), true, TEST_LOCATION );
 
   // Check that the Alignment properties can be correctly set
-  label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "BEGIN" );
-  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::HORIZONTAL_ALIGNMENT ), "BEGIN", TEST_LOCATION );
-  label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "TOP" );
-  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::VERTICAL_ALIGNMENT ), "TOP", TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::HORIZONTAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::VERTICAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+
+  // Check that text color can be properly set
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ), Color::BLUE, TEST_LOCATION );
+  // The underline color is changed as well.
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::UNDERLINE_COLOR ), Color::BLUE, TEST_LOCATION );
 
   // Check that shadow parameters can be correctly set
   label.SetProperty( TextLabel::Property::SHADOW_OFFSET, Vector2( 3.0f, 3.0f ) );
@@ -244,13 +222,10 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
   label.SetProperty( TextLabel::Property::UNDERLINE_HEIGHT, 1.0f );
   DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::UNDERLINE_HEIGHT ), 1.0f, TEST_LOCATION );
 
-  // Check that text color can be properly set
-  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLUE );
-  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ), Color::BLUE, TEST_LOCATION );
+  TextLabel label2 = TextLabel::New( "New text" );
+  DALI_TEST_CHECK( label2 );
+  DALI_TEST_EQUALS( label2.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("New text"), TEST_LOCATION );
 
-  // Toggle multi-line
-  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
-  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::MULTI_LINE ), true, TEST_LOCATION );
   END_TEST;
 }
 
@@ -261,6 +236,11 @@ int UtcDaliToolkitTextlabelBasicRenderP(void)
   TextLabel label = TextLabel::New("Test Text");
   DALI_TEST_CHECK( label );
 
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( label );
+
   label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "BEGIN" );
   label.SetProperty( TextLabel::Property::MULTI_LINE, true );
 
@@ -285,6 +265,11 @@ int UtcDaliToolkitTextlabelAtlasRenderP(void)
   TextLabel label = TextLabel::New("Test Text");
   DALI_TEST_CHECK( label );
 
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( label );
+
   // Turn on all the effects
   label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
   label.SetProperty( TextLabel::Property::MULTI_LINE, true );
@@ -292,6 +277,7 @@ int UtcDaliToolkitTextlabelAtlasRenderP(void)
   label.SetProperty( TextLabel::Property::UNDERLINE_COLOR, Color::RED );
   label.SetProperty( TextLabel::Property::SHADOW_OFFSET, Vector2( 1.0f, 1.0f ) );
   label.SetProperty( TextLabel::Property::SHADOW_COLOR, Color::BLUE );
+
   try
   {
     // Render some text with the shared atlas backend
@@ -306,3 +292,27 @@ int UtcDaliToolkitTextlabelAtlasRenderP(void)
   END_TEST;
 }
 
+int UtcDaliToolkitTextLabelLanguagesP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelLanguagesP");
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK( label );
+
+  Stage::GetCurrent().Add( label );
+
+  const std::string scripts( " привет мир, γειά σου Κόσμε, Hello world, مرحبا بالعالم, שלום עולם, "
+                             "բարեւ աշխարհը, მსოფლიოში, 안녕하세요, 你好世界, ひらがな, カタカナ, "
+                             "ওহে বিশ্ব, မင်္ဂလာပါကမ္ဘာလောက, हैलो वर्ल्ड, હેલો વર્લ્ડ, ਸਤਿ ਸ੍ਰੀ ਅਕਾਲ ਦੁਨਿਆ, ಹಲೋ ವರ್ಲ್ಡ್, "
+                             "ഹലോ വേൾഡ്, ଓଡ଼ିଆ, හෙලෝ වර්ල්ඩ්, ஹலோ உலகம், హలో వరల్డ్, "
+                             "ສະບາຍດີໂລກ, สวัสดีโลก, ជំរាបសួរពិភពលោក, "
+                             "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84." ); // these characters on the last line are emojis.
+
+  label.SetProperty( TextLabel::Property::TEXT, scripts );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), scripts, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
index b248e01..7aeb471 100644 (file)
@@ -41,7 +41,7 @@ int UtcDaliToolkitTextSelectionPopupNewP(void)
 
   DALI_TEST_CHECK( !textSelectionPopup );
 
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY, NULL );
 
   DALI_TEST_CHECK( textSelectionPopup );
   END_TEST;
@@ -61,7 +61,7 @@ int UtcDaliToolkitTextSelectionPopupCopyConstructorP(void)
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
 
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY, NULL );
   TextSelectionPopup copy( textSelectionPopup );
 
   DALI_TEST_CHECK( copy == textSelectionPopup );
@@ -85,7 +85,7 @@ int UtcDaliToolkitTextSelectionPopupAssignmentOperatorP(void)
 {
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY, NULL );
   TextSelectionPopup copy;
   copy = textSelectionPopup;
 
@@ -97,7 +97,7 @@ int UtcDaliToolkitTextSelectionPopupDownCastP(void)
 {
   ToolkitTestApplication application;
   TextSelectionPopup textSelectionPopup;
-  textSelectionPopup = TextSelectionPopup::New();
+  textSelectionPopup = TextSelectionPopup::New( TextSelectionPopup::COPY, NULL );
 
   TextSelectionPopup cast = TextSelectionPopup::DownCast( textSelectionPopup );
 
index 6f8e877..1e8c725 100644 (file)
@@ -45,6 +45,12 @@ AC_ARG_ENABLE([debug],
               [enable_debug=$enableval],
               [enable_debug=no])
 
+AC_ARG_ENABLE([i18n],
+              [AC_HELP_STRING([--enable-i18n],
+                              [Turns on internationalisation])],
+              [enable_i18n=$enableval],
+              [enable_i18n=no])
+
 # option to build JavaScript plugin
 # configure settings and output
 # --enable-javascript        // enable_javascript = yes
@@ -67,8 +73,9 @@ if test "x$enable_debug" = "xno" -a "x$enable_exportall" = "xno"; then
   DALI_TOOLKIT_CFLAGS="$DALI_TOOLKIT_CFLAGS -fvisibility=hidden -DHIDE_DALI_INTERNALS"
 fi
 
-
-
+if test "x$enable_i18n" = "xyes"; then
+  DALI_TOOLKIT_CFLAGS="$DALI_TOOLKIT_CFLAGS -DDGETTEXT_ENABLED "
+fi
 
 # Tizen Profile options
 AC_ARG_ENABLE([profile],
index aa58132..e0bc884 100644 (file)
@@ -100,6 +100,7 @@ develapishadereffectsdir =      $(develapidir)/shader-effects
 develapitransitioneffectsdir =  $(develapidir)/transition-effects
 develapistylingdir =            $(develapidir)/styling
 develapitoolbardir =            $(develapicontrolsdir)/tool-bar
+develapitextselectionpopupdir = $(develapicontrolsdir)/text-controls
 
 # devel headers
 develapibloomview_HEADERS =         $(devel_api_bloom_view_header_files)
@@ -118,6 +119,7 @@ develapistyling_HEADERS =           $(devel_api_styling_header_files)
 develapisuperblurview_HEADERS =     $(devel_api_super_blur_view_header_files)
 develapitoolbar_HEADERS =           $(devel_api_tool_bar_header_files)
 develapitransitioneffects_HEADERS = $(devel_api_transition_effects_header_files)
+develapitextselectionpopup_HEADERS = $(devel_api_text_selection_popup_header_files)
 
 # public api source
 publicapidir =                  $(topleveldir)/public-api
index e51ee1e..40da8c8 100644 (file)
@@ -36,8 +36,6 @@ namespace Toolkit
 // Magnifier
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-const std::string Magnifier::SOURCE_POSITION_PROPERTY_NAME( "source-position" );
-
 Magnifier::Magnifier()
 {
 }
@@ -86,32 +84,6 @@ void Magnifier::SetSourceActor(Actor actor)
   GetImpl(*this).SetSourceActor( actor );
 }
 
-void Magnifier::SetSourcePosition(Vector3 position)
-{
-  GetImpl(*this).SetSourcePosition( position );
-}
-
-bool Magnifier::GetFrameVisibility() const
-{
-  return GetImpl(*this).GetFrameVisibility();
-}
-
-void Magnifier::SetFrameVisibility(bool visible)
-{
-  GetImpl(*this).SetFrameVisibility(visible);
-}
-
-float Magnifier::GetMagnificationFactor() const
-{
-  return GetImpl(*this).GetMagnificationFactor();
-}
-
-void Magnifier::SetMagnificationFactor(float value)
-{
-  GetImpl(*this).SetMagnificationFactor( value );
-}
-
-
 } // namespace Toolkit
 
 } // namespace Dali
index 95c5a2b..181320d 100644 (file)
@@ -45,9 +45,33 @@ class DALI_IMPORT_API Magnifier : public Control
 {
 public:
 
-  // Custom properties
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,             ///< Reserve property indices
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000              ///< Reserve animatable property indices
+  };
 
-  static const std::string SOURCE_POSITION_PROPERTY_NAME;                   ///< Property, name "source-position",              type Vector3
+  /**
+   * @brief An enumeration of properties belonging to the Magnifier class.
+   */
+  struct Property
+  {
+    enum
+    {
+      // Event side properties
+      FRAME_VISIBILITY = PROPERTY_START_INDEX,           ///< name "frame-visibility",      Whether a frame is visible or not,         type boolean
+      MAGNIFICATION_FACTOR,                              ///< name "magnification-factor",  Larger value means greater magnification,  type float
+
+      // Animatable properties
+      SOURCE_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< name "source-position", The position of the source,  type Vector3
+    };
+  };
 
 public:
 
@@ -96,41 +120,6 @@ public:
    */
   void SetSourceActor(Actor actor);
 
-  /**
-   * Set the source camera position to render in magnifier
-   * @param[in] position The target position from which to render source.
-   */
-  void SetSourcePosition(Vector3 position);
-
-  /**
-   * Returns whether the frame is visible or not.
-   * @return true if frame is visible, false if not.
-   */
-  bool GetFrameVisibility() const;
-
-  /**
-   * Sets whether the frame part of the magnifier should be visible
-   * or not.
-   * @param[in] visible true to display frame, false to hide frame.
-   */
-  void SetFrameVisibility(bool visible);
-
-  /**
-   * Get the magnification factor of the magnifier
-   * The larger the value the larger the contents magnified.
-   * A value of 1.0f indications 1x magnification.
-   * @return Magnification factor is returned
-   */
-  float GetMagnificationFactor() const;
-
-  /**
-   * Set the magnification factor of the magnifier
-   * The larger the value the larger the contents magnified.
-   * A value of 1.0f indications 1x magnification.
-   * @param[in] value Magnification factor.
-   */
-  void SetMagnificationFactor(float value);
-
 public: // Not intended for application developers
 
   /**
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h
new file mode 100644 (file)
index 0000000..e903b77
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H__
+#define __DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 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/devel-api/controls/text-controls/text-selection-popup.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Interface used to receive the TextSelectionPopup's button callbacks.
+ */
+class TextSelectionPopupCallbackInterface
+{
+public:
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~TextSelectionPopupCallbackInterface()
+  {}
+
+  /**
+   * @brief Called when a button is touched.
+   *
+   * @param[in] button The button identifier.
+   */
+  virtual void TextPopupButtonTouched( TextSelectionPopup::Buttons button ) = 0;
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // __DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H__
index f41f667..5b85fac 100644 (file)
@@ -29,9 +29,11 @@ namespace Dali
 namespace Toolkit
 {
 
-TextSelectionPopup TextSelectionPopup::New()
+TextSelectionPopup TextSelectionPopup::New( Buttons enabledButtons,
+                                            TextSelectionPopupCallbackInterface* callbackInterface )
 {
-  return Internal::TextSelectionPopup::New();
+  return Internal::TextSelectionPopup::New( enabledButtons,
+                                            callbackInterface );
 }
 
 TextSelectionPopup::TextSelectionPopup()
index 2243f2d..3d6d5d0 100644 (file)
@@ -27,6 +27,8 @@ namespace Dali
 namespace Toolkit
 {
 
+class TextSelectionPopupCallbackInterface;
+
 namespace Internal DALI_INTERNAL
 {
 class TextSelectionPopup;
@@ -46,6 +48,17 @@ class DALI_IMPORT_API TextSelectionPopup : public Control
 {
 public:
 
+  enum Buttons
+  {
+    CUT = 1u << 0,
+    COPY = 1u << 1,
+    PASTE = 1u << 2,
+    SELECT = 1u << 3,
+    SELECT_ALL = 1u << 4,
+    CLIPBOARD = 1u << 5,
+    NONE = 1u << 6,
+  };
+
   /**
    * @brief The start and end property ranges for this control.
    */
@@ -56,15 +69,17 @@ public:
   };
 
   /**
-   * @brief An enumeration of properties belonging to the TextLabel class.
+   * @brief An enumeration of properties belonging to the TextSelectionPopup class.
    */
   struct Property
   {
     enum
     {
-
-      POPUP_MAX_SIZE,                           ///< name "popup-max-size",                The max size the Popup can be,                  type VECTOR2
-      POPUP_BACKGROUND_IMAGE,                   ///< name "popup-background-image",        The image to display for popup background       type STRING
+      POPUP_MAX_SIZE =  PROPERTY_START_INDEX,   ///< name "popup-max-size",                maximum size the Popup can be,                  type VECTOR2
+      POPUP_MIN_SIZE,                           ///< name "popup-min-size",                minimum size the Popup can be,                  type VECTOR2
+      OPTION_MAX_SIZE,                          ///< name "option-max-size",               maximum size an option can be,                  type VECTOR2
+      OPTION_MIN_SIZE,                          ///< name "option-min-size",               minimum size an option can be,                  type VECTOR2
+      OPTION_DIVIDER_SIZE,                      ///< name "option-divider-size",           size of the divider between options             type VECTOR2
       POPUP_CLIPBOARD_BUTTON_ICON_IMAGE,        ///< name "popup-clipboard-button-image",  The image to use as the popup clipboard icon,   type STRING
       POPUP_CUT_BUTTON_ICON_IMAGE,              ///< name "popup-cut-button-image",        The image to use as the popup cut icon,         type STRING
       POPUP_COPY_BUTTON_ICON_IMAGE,             ///< name "popup-copy-button-image",       The image to use as the popup copy icon,        type STRING
@@ -75,10 +90,13 @@ public:
   };
 
   /**
-   * Create the TextSelectionPopup control.
+   * Create the TextSelectionPopup control with the given set of buttons.
+   * @param[in] enabledButtons The given set of buttons to enable
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
    * @return A handle to the TextSelectionPopup control.
    */
-  static TextSelectionPopup New();
+  static TextSelectionPopup New( Buttons enabledButtons,
+                                 TextSelectionPopupCallbackInterface* callbackInterface );
 
   /**
    * @brief Creates an empty handle.
@@ -138,6 +156,6 @@ public: // Not intended for application developers
 
 } // namespace Toolkit
 
-} // namepsace Dali
+} // namespace Dali
 
 #endif // __DALI_TOOLKIT_TEXT_SELECTION_POPUP_H__
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp b/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp
new file mode 100644 (file)
index 0000000..453b12d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 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/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextSelectionToolbar TextSelectionToolbar::New()
+{
+  return Internal::TextSelectionToolbar::New();
+}
+
+TextSelectionToolbar::TextSelectionToolbar()
+{
+}
+
+TextSelectionToolbar::TextSelectionToolbar( const TextSelectionToolbar& handle )
+: Control( handle )
+{
+}
+
+TextSelectionToolbar& TextSelectionToolbar::operator=( const TextSelectionToolbar& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextSelectionToolbar::~TextSelectionToolbar()
+{
+}
+
+void TextSelectionToolbar::AddOption( Actor& option )
+{
+  GetImpl(*this).AddOption(option);
+}
+
+
+void TextSelectionToolbar::AddDivider( Actor& divider )
+{
+  GetImpl(*this).AddDivider( divider );
+}
+
+void TextSelectionToolbar::ResizeDividers( Size& size )
+{
+  GetImpl(*this).ResizeDividers( size );
+}
+
+TextSelectionToolbar TextSelectionToolbar::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextSelectionToolbar, Internal::TextSelectionToolbar>(handle);
+}
+
+TextSelectionToolbar::TextSelectionToolbar( Internal::TextSelectionToolbar& implementation )
+: Control(implementation)
+{
+}
+
+TextSelectionToolbar::TextSelectionToolbar( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextSelectionToolbar>( internal );
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h
new file mode 100644 (file)
index 0000000..31fca5c
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef __DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H__
+#define __DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H__
+
+/*
+ * Copyright (c) 2015 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/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TextSelectionToolbar;
+}
+
+/**
+ * @brief A control which provides a Popup with a number of buttons
+ *
+ * The style of the pop can be set through style sheets, this includes the images for the buttons
+ * A Show and Hide API is provided.
+ *
+ * If the buttons exceed the size constraints of the popup then it will offer scrolling.
+ *
+ *
+ */
+class DALI_IMPORT_API TextSelectionToolbar : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the TextSelectionToolbar class.
+   */
+  struct Property
+  {
+    enum
+    {
+      MAX_SIZE =  PROPERTY_START_INDEX   ///< name "popup-max-size",                The maximum size the Popup can be,              type VECTOR2
+    };
+  };
+
+  /**
+   * Create the TextSelectionToolbar control.
+   * @return A handle to the TextSelectionToolbar control.
+   */
+  static TextSelectionToolbar New();
+
+  /**
+   * @brief Creates an empty handle.
+   */
+  TextSelectionToolbar();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] handle The handle to copy from.
+   */
+  TextSelectionToolbar( const TextSelectionToolbar& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] handle The handle to copy from.
+   * @return A reference to this.
+   */
+  TextSelectionToolbar& operator=( const TextSelectionToolbar& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TextSelectionToolbar();
+
+
+  /**
+   * @brief Add a option to the the Tool bar
+   * @param[in] option Option actor to add
+   */
+  void AddOption( Actor& option );
+
+  /**
+   * @brief Add a divider to the the Tool bar
+   * @param[in] divider Actor to be used as divider
+   */
+  void AddDivider( Actor& divider );
+
+  /**
+   *  @brief ResizeDividers
+   *  @param[in] size New size of dividers, provide 0 for height to automatically set height
+   */
+  void ResizeDividers( Size& size );
+
+  /**
+   * @brief Downcast a handle to TextSelectionToolbar.
+   *
+   * If the BaseHandle points is a TextSelectionToolbar the downcast returns a valid handle.
+   * If not the returned handle is left empty.
+   *
+   * @param[in] handle Handle to an object
+   * @return handle to a TextSelectionToolbar or an empty handle
+   */
+  static TextSelectionToolbar DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in] implementation The Control implementation.
+   */
+  DALI_INTERNAL TextSelectionToolbar( Internal::TextSelectionToolbar& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL TextSelectionToolbar( Dali::Internal::CustomActor* internal );
+
+}; // Class TextSelectionToolbar
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H__
index f10a341..71202e2 100755 (executable)
@@ -17,6 +17,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/controls/slider/slider.cpp \
   $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.cpp \
   $(devel_api_src_dir)/controls/text-controls/text-selection-popup.cpp \
+  $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.cpp \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.cpp \
   $(devel_api_src_dir)/focus-manager/keyinput-focus-manager.cpp \
   $(devel_api_src_dir)/styling/style-manager.cpp \
@@ -100,8 +101,9 @@ devel_api_shader_effects_header_files = \
 devel_api_super_blur_view_header_files = \
   $(devel_api_src_dir)/controls/super-blur-view/super-blur-view.h
 
-devel_api_text_selection_popup_header_files = \
-  $(devel_api_src_dir)/controls/text-controls/text-selection-popup.h
+devel_api_text_controls_header_files = \
+  $(devel_api_src_dir)/controls/text-controls/text-selection-popup.h \
+  $(devel_api_src_dir)/controls/text-controls/text-selection-toolbar.h
 
 devel_api_tool_bar_header_files = \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.h
diff --git a/dali-toolkit/images/selection-popup-bg#.png b/dali-toolkit/images/selection-popup-bg#.png
new file mode 100755 (executable)
index 0000000..3eac19f
Binary files /dev/null and b/dali-toolkit/images/selection-popup-bg#.png differ
index 15baf37..a5f0462 100644 (file)
@@ -690,7 +690,8 @@ void AtlasManager::UploadImage( const BufferImage& image,
 
 void AtlasManager::GenerateMeshData( ImageId id,
                                      const Vector2& position,
-                                     Toolkit::AtlasManager::Mesh2D& meshData )
+                                     Toolkit::AtlasManager::Mesh2D& meshData,
+                                     bool addReference )
 {
   // Read the atlas Id to use for this image
   SizeType imageId = id - 1u;
@@ -711,8 +712,11 @@ void AtlasManager::GenerateMeshData( ImageId id,
 
   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
 
-  // Mesh created so increase the reference count
-  mImageList[ imageId ].mCount++;
+  // Mesh created so increase the reference count, if we're asked to
+  if ( addReference )
+  {
+    mImageList[ imageId ].mCount++;
+  }
 }
 
 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
index 5336e1b..88f3302 100644 (file)
@@ -112,7 +112,8 @@ public:
    */
   void GenerateMeshData( ImageId id,
                          const Vector2& position,
-                         Toolkit::AtlasManager::Mesh2D& mesh );
+                         Toolkit::AtlasManager::Mesh2D& mesh,
+                         bool addReference );
 
   /**
    * @copydoc Toolkit::AtlasManager::StitchMesh
index 977c8dc..e6b041c 100644 (file)
@@ -69,11 +69,13 @@ bool AtlasManager::Remove( ImageId id )
 
 void AtlasManager::GenerateMeshData( ImageId id,
                                      const Vector2& position,
-                                     Mesh2D& mesh )
+                                     Mesh2D& mesh,
+                                     bool addReference )
 {
   GetImplementation(*this).GenerateMeshData( id,
                                              position,
-                                             mesh );
+                                             mesh,
+                                             addReference );
 }
 
 void AtlasManager::StitchMesh( Mesh2D& first,
index f0ecc22..79eb9b7 100644 (file)
@@ -286,10 +286,12 @@ public:
    * @param[in] id Image Id returned in the AtlasSlot from the add operation
    * @param[in] position position of the resulting mesh in model space
    * @param[out] mesh Mesh Data Object to populate with mesh data
+   * @param[in] addReference Whether to increase the internal reference count for image or not
    */
   void GenerateMeshData( ImageId id,
                          const Vector2& position,
-                         Mesh2D& mesh );
+                         Mesh2D& mesh,
+                         bool addReference = true );
 
   /**
    * @brief Append second mesh to the first mesh
index 287663c..fbe8c33 100644 (file)
@@ -49,11 +49,11 @@ Actor SetupActor( const TreeNode& child, Actor& actor, const Replacement& consta
   // this has already been set as a generic property.
   if( !IsVector3( child, "parent-origin") )
   {
-    if( OptionalVector3 v = IsVector3(child, "parent-origin") )
+    if( OptionalVector3 v = constant.IsVector3( IsChild(child, "parent-origin") ) )
     {
       actor.SetParentOrigin( *v );
     }
-    else if( OptionalString origin = IsString(child, "parent-origin") )
+    else if( OptionalString origin = constant.IsString( IsChild(child, "parent-origin") ) )
     {
       actor.SetParentOrigin( GetAnchorConstant(*origin) );
     }
@@ -61,11 +61,11 @@ Actor SetupActor( const TreeNode& child, Actor& actor, const Replacement& consta
 
   if( !IsVector3(child, "anchor-point") )
   {
-    if( OptionalVector3 v = IsVector3(child, "anchor-point") )
+    if( OptionalVector3 v = constant.IsVector3( IsChild(child, "anchor-point") ) )
     {
       actor.SetAnchorPoint( *v );
     }
-    else if( OptionalString anchor = IsString(child, "anchor-point") )
+    else if( OptionalString anchor = constant.IsString( IsChild(child, "anchor-point") ) )
     {
       actor.SetAnchorPoint( GetAnchorConstant(*anchor) );
     }
@@ -87,7 +87,7 @@ Actor SetupActor( const TreeNode& child, Actor& actor, const Replacement& consta
       {
         if( Property::INVALID_INDEX == index )
         {
-          actor.RegisterProperty( key, value );
+          actor.RegisterProperty( key, value, Property::READ_WRITE );
         }
         else
         {
index 12a87c5..ddf2cda 100644 (file)
@@ -134,7 +134,7 @@ AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
   }
   else
   {
-    DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Anchor Constant" );
+    DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Alpha Constant" );
     return Dali::AlphaFunction::DEFAULT;
   }
 }
index 5d5e4b9..d4a2a3e 100644 (file)
@@ -176,11 +176,6 @@ std::string PropertyValueToString( const Property::Value& value )
       ret = std::string("Map Size=") + ToString( value.Get<Property::Map>().Count() );
       break;
     }
-    case Property::TYPE_COUNT:
-    {
-      ret = "";
-      break;
-    }
   }
 
   return ret;
@@ -721,11 +716,12 @@ FrameBufferImage Builder::GetFrameBufferImage( const std::string &name, const Re
     {
       if( OptionalChild image = IsChild( *images, name ) )
       {
-        Dali::Property::Value propertyMap(Property::MAP);
-        if( SetPropertyFromNode( *image, Property::MAP, propertyMap, constant ) )
+        Dali::Property::Value property(Property::MAP);
+        if( SetPropertyFromNode( *image, Property::MAP, property, constant ) )
         {
-          propertyMap.SetValue(KEYNAME_TYPE, Property::Value(std::string("FrameBufferImage")));
-          ret = FrameBufferImage::DownCast( Dali::Scripting::NewImage( propertyMap ) );
+          Property::Map* map = property.GetMap();
+          (*map)[ KEYNAME_TYPE ] = Property::Value(std::string("FrameBufferImage") );
+          ret = FrameBufferImage::DownCast( Dali::Scripting::NewImage( property ) );
           mFrameBufferImageLut[ name ] = ret;
         }
       }
index cd90217..a1ed104 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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,8 @@
 
 // EXTERNAL INCLUDES
 #include <sstream>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
 #include <dali/devel-api/adaptor-framework/color-controller.h>
 
 // INTERNAL INCLUDES
@@ -210,11 +212,8 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
     {
       if( OptionalUnsignedInt v = replacer.IsUnsignedInteger( node) )
       {
-        if( *v >= 0 ) // with a loss of resolution....
-        {
-          value = *v;
-          done = true;
-        }
+        value = *v;
+        done = true;
       }
       break;
     }
@@ -352,18 +351,19 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
       else if(node.Size())
       {
         value = Property::Value(Property::ARRAY);
+        Property::Array* array = value.GetArray();
         unsigned int i = 0;
         TreeNode::ConstIterator iter(node.CBegin());
         for( ; i < node.Size(); ++i, ++iter)
         {
-          Property::Value v;
-          if( SetPropertyFromNode( (*iter).second, v, replacer ) )
+          Property::Value childValue;
+          if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
           {
-            value.AppendItem(v);
+            array->PushBack( childValue );
           }
         }
 
-        if( value.GetSize() == static_cast<int>(node.Size()) )
+        if( array->Count() == node.Size() )
         {
           done = true;
         }
@@ -383,18 +383,19 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
       else if(node.Size())
       {
         value = Property::Value(Property::MAP);
+        Property::Map* map = value.GetMap();
         unsigned int i = 0;
         TreeNode::ConstIterator iter(node.CBegin());
         for( ; i < node.Size(); ++i, ++iter)
         {
-          Property::Value v;
-          if( SetPropertyFromNode( (*iter).second, v, replacer ) )
+          Property::Value childValue;
+          if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
           {
-            value.SetValue( (*iter).first, v );
+            map->Insert( (*iter).first, childValue );
           }
         }
 
-        if( value.GetSize() == static_cast<int>(node.Size()) )
+        if( map->Count() == node.Size() )
         {
           done = true;
         }
@@ -405,7 +406,6 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Type type, Property::V
       }
       break;
     }
-    case Property::TYPE_COUNT:
     case Property::NONE:
     {
       break;
@@ -490,13 +490,14 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
         else
         {
           value = Property::Value(Property::ARRAY);
-          Property::Value v;
+          Property::Array* array = value.GetArray();
 
           for(TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
+            Property::Value childValue;
+            if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
             {
-              value.AppendItem(v);
+              array->PushBack( childValue );
               done = true;
             }
           }
@@ -514,12 +515,13 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
         if( ((*iter).first) == 0 )
         {
           value = Property::Value(Property::ARRAY);
-          Property::Value v;
+          Property::Array* array = value.GetArray();
           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
+            Property::Value childValue;
+            if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
             {
-              value.AppendItem(v);
+              array->PushBack( childValue );
               done = true;
             }
           }
@@ -527,12 +529,13 @@ bool SetPropertyFromNode( const TreeNode& node, Property::Value& value,
         else
         {
           value = Property::Value(Property::MAP);
-          Property::Value v;
+          Property::Map* map = value.GetMap();
           for(unsigned int i = 0; i < node.Size(); ++i, ++iter)
           {
-            if( SetPropertyFromNode( (*iter).second, v, replacer ) )
+            Property::Value childValue;
+            if( SetPropertyFromNode( (*iter).second, childValue, replacer ) )
             {
-              value.SetValue((*iter).first, v);
+              map->Insert( (*iter).first, childValue );
               done = true;
             }
           }
index 7161df5..f080ba3 100644 (file)
@@ -45,331 +45,67 @@ BaseHandle Create()
 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Alignment, Toolkit::Control, Create )
 DALI_TYPE_REGISTRATION_END()
 
-struct ScaleToFillConstraint
-{
-  /**
-   * @param padding to be added.
-   */
-  ScaleToFillConstraint( const Toolkit::Alignment::Padding& padding )
-  : mPadding( padding )
-  {}
-
-  /**
-   * Called by render thread
-   */
-  Vector3 operator()( const Vector3& currentSize,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-    return GetSize( currentSize, parentSize );
-  }
-
-  inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
-  {
-    const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
-    const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
-
-    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
-    if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 ) )
-    {
-      // no point trying to squeeze actors into this small size
-      return Vector3::ZERO;
-    }
-    return  Vector3( parentSizeWidth, parentSizeHeight, parentSize.depth );
-  }
-
-  const Toolkit::Alignment::Padding mPadding;
-};
-
-struct ScaleToFitKeepAspectConstraint
-{
-  /**
-   * @param padding to be added.
-   */
-  ScaleToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
-  : mPadding( padding ),
-    mSizeStored( false ),
-    mOriginalSize()
-  {}
-
-  /**
-   * Called by render thread
-   */
-  Vector3 operator()( const Vector3& currentSize,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-    return GetSize( currentSize, parentSize );
-  }
-
-  inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
-  {
-    if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
-    {
-      mOriginalSize = currentSize;
-      mSizeStored = true;
-    }
-
-    const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
-    const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
-
-    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
-    if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
-        ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
-    {
-      // no point trying to squeeze actors into this small size
-      return Vector3::ZERO;
-    }
-
-    return mOriginalSize * std::min( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
-  }
-
-  const Toolkit::Alignment::Padding mPadding;
-        bool                        mSizeStored;
-        Vector3                     mOriginalSize;
-};
-
-struct ScaleToFillKeepAspectConstraint
-{
-  /**
-   * @param padding to be added.
-   */
-  ScaleToFillKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
-  : mPadding( padding ),
-    mSizeStored( false ),
-    mOriginalSize()
-  { }
-
-  /**
-   * Called by render thread
-   */
-  Vector3 operator()( const Vector3& currentSize,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-    return GetSize( currentSize, parentSize );
-  }
-
-  Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
-  {
-    if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
-    {
-      mOriginalSize = currentSize;
-      mSizeStored = true;
-    }
-
-    const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
-    const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
-
-    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
-    if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
-        ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
-    {
-      // no point trying to squeeze actors into this small size
-      return Vector3::ZERO;
-    }
-
-    return mOriginalSize * std::max( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
-  }
-
-  const Toolkit::Alignment::Padding mPadding;
-        bool                        mSizeStored;
-        Vector3                     mOriginalSize;
-};
-
-struct ShrinkToFitConstraint
-{
-  /**
-   * @param padding to be added.
-   */
-  ShrinkToFitConstraint( const Toolkit::Alignment::Padding& padding )
-  : mPadding( padding ),
-    mSizeStored( false ),
-    mOriginalSize()
-  {}
-
-  /**
-   * Called by render thread
-   */
-  Vector3 operator()( const Vector3& currentSize,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-    return GetSize( currentSize, parentSize );
-  }
-
-  Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
-  {
-    if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
-    {
-      mOriginalSize = currentSize;
-      mSizeStored = true;
-    }
-
-    const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
-    const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
-
-    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
-    if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
-        ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
-    {
-      // no point trying to squeeze actors into this small size
-      return Vector3::ZERO;
-    }
-
-    return Vector3( std::min( parentSizeWidth, mOriginalSize.width ), std::min( parentSizeHeight, mOriginalSize.height ), std::min( parentSize.depth, mOriginalSize.depth ) );
-  }
-
-  const Toolkit::Alignment::Padding mPadding;
-        bool                        mSizeStored;
-        Vector3                     mOriginalSize;
-};
-
-/**
- * Constraint that uses naturalSize if it fits inside parent and parent size if not. It also adds some padding pixels
- */
-struct ShrinkToFitKeepAspectConstraint
-{
-  /**
-   * @param padding to be added.
-   */
-  ShrinkToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
-  : mPadding( padding ),
-    mSizeStored( false ),
-    mOriginalSize()
-  {}
-
-  /**
-   * Called by render thread
-   */
-  Vector3 operator()( const Vector3& currentSize,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-    return GetSize( currentSize, parentSize );
-  }
-
-  inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
-  {
-    if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
-    {
-      mOriginalSize = currentSize;
-      mSizeStored = true;
-    }
-
-    const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
-    const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
-
-    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
-    if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
-        ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
-    {
-      // no point trying to squeeze actors into this small size
-      return Vector3::ZERO;
-    }
-
-    return Vector3( ShrinkInside( Vector2( parentSizeWidth, parentSizeHeight ), Vector2( mOriginalSize ) ) );
-  }
-
-  const Toolkit::Alignment::Padding mPadding;
-        bool                        mSizeStored;
-        Vector3                     mOriginalSize;
-};
-
 /**
- * Constraint that modifies the contained actor taking into account the padding value.
+ * @param padding The padding value
+ * @param horizontalAlignment The horizontal alignment.
+ * @param verticalAlignment The vertical alignment.
+ * @param currentSize of the object
+ * @param parentSize
  */
-struct PositionConstraint
+inline Vector3 GetPosition( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment,
+                            const Vector2& currentSize, const Vector2& parentSize )
 {
-  /**
-   * @param padding The padding value
-   * @param horizontalAlignment The horizontal alignment.
-   * @param verticalAlignment The vertical alignment.
-   */
-  PositionConstraint( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment )
-  : mPadding( padding ),
-    mHorizontalAlignment( horizontalAlignment ),
-    mVerticalAlignment( verticalAlignment )
-  {}
-
-  /**
-   * Called by render thread.
-   */
-  Vector3 operator()( const Vector3& currentPosition,
-                      const PropertyInput& currentSizeProperty,
-                      const PropertyInput& parentSizeProperty )
-  {
-    const Vector3& currentSize( currentSizeProperty.GetVector3() );
-    const Vector3& parentSize( parentSizeProperty.GetVector3() );
-
-    return GetPosition( currentSize, parentSize );
-  }
+  Vector3 position( 0.f, 0.f, 0.f );
 
-  inline Vector3 GetPosition( const Vector3& currentSize, const Vector3& parentSize )
+  switch( horizontalAlignment )
   {
-    Vector3 position( 0.f, 0.f, 0.f );
-
-    switch( mHorizontalAlignment )
-    {
     case Dali::Toolkit::Alignment::HorizontalLeft:
     {
-      position.x += mPadding.left;
-      break;
-    }
-    case Dali::Toolkit::Alignment::HorizontalCenter:
-    {
-      if( currentSize.width + mPadding.left + mPadding.right >= parentSize.width )
-      {
-        position.x += 0.5f * ( mPadding.left - mPadding.right );
-      }
+      position.x += padding.left;
       break;
     }
     case Dali::Toolkit::Alignment::HorizontalRight:
     {
-      position.x -= mPadding.right;
+      position.x -= padding.right;
       break;
     }
-    default:
+    case Dali::Toolkit::Alignment::HorizontalCenter: // FALLTHROUGH
+    default: // use center as default
     {
-      DALI_ASSERT_ALWAYS( !"Wrong horizontal alignment value" );
+      if( currentSize.width + padding.left + padding.right >= parentSize.width )
+      {
+        position.x += 0.5f * ( padding.left - padding.right );
+      }
       break;
     }
-    }
+  }
 
-    switch( mVerticalAlignment )
-    {
+  switch( verticalAlignment )
+  {
     case Dali::Toolkit::Alignment::VerticalTop:
     {
-      position.y += mPadding.top;
-      break;
-    }
-    case Dali::Toolkit::Alignment::VerticalCenter:
-    {
-      if( currentSize.height + mPadding.top + mPadding.bottom >= parentSize.height )
-      {
-        position.y += 0.5f * ( mPadding.top - mPadding.bottom );
-      }
+      position.y += padding.top;
       break;
     }
     case Dali::Toolkit::Alignment::VerticalBottom:
     {
-      position.y -= mPadding.bottom;
+      position.y -= padding.bottom;
       break;
     }
-    default:
+    case Dali::Toolkit::Alignment::VerticalCenter: // FALLTHROUGH
+    default: // use center as default
     {
-      DALI_ASSERT_ALWAYS( !"Wrong vertical alignment value" );
+      if( currentSize.height + padding.top + padding.bottom >= parentSize.height )
+      {
+        position.y += 0.5f * ( padding.top - padding.bottom );
+      }
       break;
     }
-    }
-
-    return position;
   }
 
-  const Toolkit::Alignment::Padding mPadding;
-  const Toolkit::Alignment::Type mHorizontalAlignment;
-  const Toolkit::Alignment::Type mVerticalAlignment;
-};
+  return position;
+}
+
 } // namespace
 
 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
@@ -482,67 +218,73 @@ void Alignment::OnRelayout( const Vector2& size, RelayoutContainer& container )
     child.SetAnchorPoint( anchorPointAndParentOrigin );
     child.SetParentOrigin( anchorPointAndParentOrigin );
 
-    Vector3 currentChildSize( child.GetTargetSize() );
-    if( currentChildSize == Vector3::ZERO )
+    Vector2 currentChildSize( child.GetTargetSize().GetVectorXY() );
+    if( currentChildSize == Vector2::ZERO )
     {
       currentChildSize = child.GetNaturalSize();
     }
 
     bool renegotiate = true;
-    Vector3 newChildSize;
+    Vector2 newChildSize;
+    newChildSize.width  = size.width - ( mPadding.left + mPadding.right );
+    newChildSize.height = size.height- (  mPadding.top + mPadding.bottom );
 
-    switch( mScaling )
+    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
+    if( ( newChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( newChildSize.height > Math::MACHINE_EPSILON_1000 ) &&
+        ( currentChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( currentChildSize.height > Math::MACHINE_EPSILON_1000 ) )
     {
-      case Toolkit::Alignment::ScaleNone:
-      {
-        // Nothing to do but needed just to not to jump to the default.
-        newChildSize = currentChildSize;
-        renegotiate = false;
-        break;
-      }
-      case Toolkit::Alignment::ScaleToFill:
-      {
-        ScaleToFillConstraint constraint( mPadding );
-        newChildSize = constraint.GetSize( currentChildSize, Vector3(size) ) ;
-        break;
-      }
-      case Toolkit::Alignment::ScaleToFitKeepAspect:
-      {
-        ScaleToFitKeepAspectConstraint constraint( mPadding );
-        newChildSize = constraint.GetSize( currentChildSize, Vector3(size) ) ;
-        break;
-      }
-      case Toolkit::Alignment::ScaleToFillKeepAspect:
-      {
-        ScaleToFillKeepAspectConstraint constraint( mPadding );
-        newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
-        break;
-      }
-      case Toolkit::Alignment::ShrinkToFit:
-      {
-        ShrinkToFitConstraint constraint( mPadding );
-        newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
-        break;
-      }
-      case Toolkit::Alignment::ShrinkToFitKeepAspect:
-      {
-        ShrinkToFitKeepAspectConstraint constraint( mPadding );
-        newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
-        break;
-      }
-      default:
+      // no point trying to squeeze actors into too small size
+      switch( mScaling )
       {
-        DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
-        break;
+        case Toolkit::Alignment::ScaleNone:
+        {
+          // Nothing to do
+          renegotiate = false;
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFill:
+        {
+          // Nothing to do, newChildSize is already full size minus padding
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFitKeepAspect:
+        {
+          newChildSize = currentChildSize * std::min( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFillKeepAspect:
+        {
+          newChildSize = currentChildSize * std::max( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ShrinkToFit:
+        {
+          newChildSize = Vector2( std::min( newChildSize.width, currentChildSize.width ), std::min( newChildSize.height, currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ShrinkToFitKeepAspect:
+        {
+          // check source size vs target size to see if we need to shrink
+          float widthScale = ( newChildSize.width < currentChildSize.width ) ? (newChildSize.width / currentChildSize.width) : 1.f;
+          float heightScale = ( newChildSize.height < currentChildSize.height ) ? (newChildSize.height / currentChildSize.height) : 1.0f;
+          // use smaller of the scales
+          float scale = std::min( widthScale, heightScale );
+          // check if we need to scale
+          if( scale < 1.0f )
+          {
+            // scale natural size to fit inside
+            newChildSize *= scale;
+          }
+          break;
+        }
       }
     }
 
-    PositionConstraint positionConstraint(mPadding, mHorizontal, mVertical);
-    child.SetPosition( positionConstraint.GetPosition(newChildSize, currentChildSize) );
+    child.SetPosition( GetPosition( mPadding, mHorizontal, mVertical , newChildSize, currentChildSize ) );
 
     if( renegotiate )
     {
-      container.Add( child, Vector2(newChildSize) );
+      container.Add( child, newChildSize );
     }
   }
 }
index bfa4617..d956e36 100644 (file)
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/render-tasks/render-task-list.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/object/type-registry-helper.h>
 
-using namespace Dali;
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
 
 namespace // unnamed namespace
 {
 
+
+Dali::BaseHandle Create()
+{
+  return Toolkit::Magnifier::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Magnifier, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Magnifier, "frame-visibility",     BOOLEAN, FRAME_VISIBILITY     )
+DALI_PROPERTY_REGISTRATION( Toolkit, Magnifier, "magnification-factor", FLOAT,   MAGNIFICATION_FACTOR )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Magnifier, "source-position", VECTOR3, SOURCE_POSITION )
+
+DALI_TYPE_REGISTRATION_END()
+
 const char* DEFAULT_FRAME_IMAGE_PATH = DALI_IMAGE_DIR "magnifier-image-frame.png";
 
 const float IMAGE_BORDER_INDENT = 14.0f;            ///< Indent of border in pixels.
@@ -92,16 +116,7 @@ struct RenderTaskViewportSizeConstraint
   }
 };
 
-}
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
+} // unnamed namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Magnifier
@@ -124,7 +139,6 @@ Dali::Toolkit::Magnifier Magnifier::New()
 
 Magnifier::Magnifier()
 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS ) ),
-  mPropertySourcePosition(Property::INVALID_INDEX),
   mDefaultCameraDistance(1000.f),
   mActorSize(Vector3::ZERO),
   mMagnificationFactor(1.0f)
@@ -136,15 +150,9 @@ void Magnifier::SetSourceActor(Actor actor)
   mTask.SetSourceActor( actor );
 }
 
-void Magnifier::SetSourcePosition(const Vector3& position)
-{
-  Self().SetProperty(mPropertySourcePosition, position);
-}
-
 void Magnifier::Initialize()
 {
   Actor self = Self();
-  mPropertySourcePosition = self.RegisterProperty( Toolkit::Magnifier::SOURCE_POSITION_PROPERTY_NAME, Vector3::ZERO );
   Vector2 stageSize(Stage::GetCurrent().GetSize());
 
   // NOTE:
@@ -161,7 +169,7 @@ void Magnifier::Initialize()
   Stage().GetCurrent().Add(mSourceActor);
   mSourceActor.SetParentOrigin(ParentOrigin::CENTER);
   Constraint constraint = Constraint::New<Vector3>( mSourceActor, Actor::Property::POSITION, EqualToConstraint() );
-  constraint.AddSource( Source( self, mPropertySourcePosition ) );
+  constraint.AddSource( Source( self, Toolkit::Magnifier::Property::SOURCE_POSITION ) );
   constraint.Apply();
 
   // create the render task this will render content on top of everything
@@ -316,6 +324,56 @@ void Magnifier::Update()
   mCameraActor.SetAspectRatio( worldSize.width / worldSize.height );
 }
 
+void Magnifier::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Magnifier magnifier = Toolkit::Magnifier::DownCast( Dali::BaseHandle( object ) );
+
+  if( magnifier )
+  {
+    Magnifier& magnifierImpl( GetImpl( magnifier ) );
+    switch( index )
+    {
+      case Toolkit::Magnifier::Property::FRAME_VISIBILITY:
+      {
+        magnifierImpl.SetFrameVisibility( value.Get< bool >() );
+        break;
+      }
+      case Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR:
+      {
+        magnifierImpl.SetMagnificationFactor( value.Get< float >() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Magnifier::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Magnifier magnifier = Toolkit::Magnifier::DownCast( Dali::BaseHandle( object ) );
+
+  if( magnifier )
+  {
+    Magnifier& magnifierImpl( GetImpl( magnifier ) );
+    switch( index )
+    {
+      case Toolkit::Magnifier::Property::FRAME_VISIBILITY:
+      {
+        value = magnifierImpl.GetFrameVisibility();
+        break;
+      }
+      case Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR:
+      {
+        value = magnifierImpl.GetMagnificationFactor();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index d4fea4e..d8b990f 100644 (file)
@@ -62,27 +62,30 @@ public:
   void SetSourceActor(Actor actor);
 
   /**
-   * @copydoc Toolkit::ImageView::SetSourcePosition
-   */
-  void SetSourcePosition(const Vector3& position);
-
-  /**
-   * @copydoc Toolkit::ImageView::GetFrameVisibility
+   * Returns whether the frame is visible or not.
+   * @return true if frame is visible, false if not.
    */
   bool GetFrameVisibility() const;
 
   /**
-   * @copydoc Toolkit::ImageView::SetFrameVisibility
+   * Sets whether the frame part of the magnifier should be visible or not.
+   * @param[in] visible true to display frame, false to hide frame.
    */
   void SetFrameVisibility(bool visible);
 
   /**
-   * @copydoc Toolkit::ImageView::GetMagnificationFactor
+   * Get the magnification factor of the magnifier
+   * The larger the value the larger the contents magnified.
+   * A value of 1.0f indications 1x magnification.
+   * @return Magnification factor is returned
    */
   float GetMagnificationFactor() const;
 
   /**
-   * @copydoc Toolkit::ImageView::SetMagnificationFactor
+   * Set the magnification factor of the magnifier
+   * The larger the value the larger the contents magnified.
+   * A value of 1.0f indications 1x magnification.
+   * @param[in] value Magnification factor.
    */
   void SetMagnificationFactor(float value);
 
@@ -91,6 +94,24 @@ public:
    */
   void Update();
 
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
 protected:
 
   /**
@@ -132,7 +153,6 @@ private:
   RenderTask mTask;                             ///< Render Task to render the source actor contents.
   CameraActor mCameraActor;                     ///< CameraActor attached to RenderTask
   ImageActor mFrame;                            ///< The Magnifier Frame
-  Property::Index mPropertySourcePosition;      ///< Source Position ("source-position")
   Actor mSourceActor;                           ///< Source Delegate Actor represents the source position to read.
   float mDefaultCameraDistance;                 ///< Default RenderTask's camera distance from target.
   Vector3 mActorSize;                           ///< The Actor size
index e01dfbd..d828897 100755 (executable)
 
 // EXTERNAL INCLUDES
 #include <cstring> // for strcmp
-#include <dali/integration-api/debug.h>
 #include <dali/public-api/animation/constraint.h>
 #include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/property-array.h>
 #include <dali/devel-api/object/type-registry-helper.h>
-#include <dali/public-api/images/resource-image.h>
+#include <dali/integration-api/debug.h>
+
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
@@ -599,16 +601,19 @@ void ScrollBar::SetProperty( BaseObject* object, Property::Index index, const Pr
       }
       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
       {
-        Dali::Vector<float> positions;
-        size_t positionCount = value.GetSize();
-        positions.Resize( positionCount );
-
-        for( size_t i = 0; i != positionCount; ++i )
+        Property::Array* array = value.GetArray();
+        if( array )
         {
-          value.GetItem(i).Get( positions[i] );
+          Dali::Vector<float> positions;
+          size_t positionCount = array->Count();
+          positions.Resize( positionCount );
+          for( size_t i = 0; i != positionCount; ++i )
+          {
+            array->GetElementAt( i ).Get( positions[i] );
+          }
+
+          scrollBarImpl.SetScrollPositionIntervals(positions);
         }
-
-        scrollBarImpl.SetScrollPositionIntervals(positions);
         break;
       }
     }
@@ -653,12 +658,13 @@ Property::Value ScrollBar::GetProperty( BaseObject* object, Property::Index inde
       }
       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
       {
-        Property::Value value;
+        Property::Value value( Property::ARRAY );
+        Property::Array* array = value.GetArray();
         Dali::Vector<float> positions = scrollBarImpl.GetScrollPositionIntervals();
-        size_t positionCount( positions.Size() );
+        size_t positionCount( array->Count() );
         for( size_t i( 0 ); i != positionCount; ++i )
         {
-          value.AppendItem( positions[i] );
+          array->PushBack( positions[i] );
         }
         break;
       }
index bb13f59..13ab888 100644 (file)
@@ -53,6 +53,8 @@ DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-direction",
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout-orientation",  INTEGER,  LAYOUT_ORIENTATION)
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scroll-content-size", FLOAT,    SCROLL_CONTENT_SIZE)
 
+DALI_SIGNAL_REGISTRATION(              Toolkit, ItemView, "layout-activated",    LAYOUT_ACTIVATED_SIGNAL )
+
 DALI_TYPE_REGISTRATION_END()
 
 const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
@@ -422,6 +424,11 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz
     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished);
     mScrollAnimation.Play();
   }
+  else
+  {
+    // Emit the layout activated signal
+    mLayoutActivatedSignal.Emit();
+  }
 
   AnimateScrollOvershoot(0.0f);
   mScrollOvershoot = 0.0f;
@@ -1298,6 +1305,9 @@ void ItemView::OnLayoutActivationScrollFinished(Animation& source)
   RemoveAnimation(mScrollAnimation);
   mRefreshEnabled = true;
   DoRefresh(GetCurrentLayoutPosition(0), true);
+
+  // Emit the layout activated signal
+  mLayoutActivatedSignal.Emit();
 }
 
 void ItemView::OnOvershootOnFinished(Animation& animation)
@@ -1624,6 +1634,26 @@ void ItemView::OnScrollPositionChanged( float position )
   DoRefresh(position, false); // No need to cache extra items.
 }
 
+bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), LAYOUT_ACTIVATED_SIGNAL ) )
+  {
+    itemView.LayoutActivatedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 16f0b0a..b6a2d96 100644 (file)
@@ -53,6 +53,11 @@ class ItemView : public Scrollable
 {
 public:
 
+  // Signals
+  typedef Toolkit::ItemView::LayoutActivatedSignalType LayoutActivatedSignalType;
+
+public:
+
   /**
    * Create a new ItemView.
    * @param[in] factory The factory which provides ItemView with items.
@@ -284,6 +289,25 @@ public:
    */
   void GetItemsRange(ItemRange& range);
 
+  /**
+   * @copydoc Toolkit::ItemView::LayoutActivatedSignal()
+   */
+  LayoutActivatedSignalType& LayoutActivatedSignal()
+  {
+    return mLayoutActivatedSignal;
+  }
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
 private:
 
   /**
@@ -593,6 +617,8 @@ private:
 
   Vector3 mItemsParentOrigin;
   Vector3 mItemsAnchorPoint;
+
+  LayoutActivatedSignalType mLayoutActivatedSignal;
 };
 
 } // namespace Internal
index 439dd8f..f12b873 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h>
 
-//INTERNAL INCLUDES
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
+
+// INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
 
 namespace Dali
@@ -47,9 +50,10 @@ ScrollViewPagePathEffect::ScrollViewPagePathEffect(Path path, const Vector3& for
 
   //Create linear constrainer
   pointsProperty = Property::Value(Property::ARRAY);
-  pointsProperty.AppendItem(0.0f);
-  pointsProperty.AppendItem(1.0f);
-  pointsProperty.AppendItem(0.0f);
+  Property::Array* array = pointsProperty.GetArray();
+  array->PushBack(0.0f);
+  array->PushBack(1.0f);
+  array->PushBack(0.0f);
   mLinearConstrainer = Dali::LinearConstrainer::New();
   mLinearConstrainer.SetProperty( LinearConstrainer::Property::VALUE, pointsProperty );
 }
index a7b105c..38ceffe 100755 (executable)
@@ -724,7 +724,7 @@ float Slider::MarkFilter( float value )
   const float MARK_TOLERANCE = GetMarkTolerance();
 
   float mark;
-  for( std::size_t i = 0; i < mMarks.Size(); ++i)
+  for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
   {
     const Property::Value& propertyValue = mMarks[i];
     propertyValue.Get( mark );
@@ -746,7 +746,7 @@ float Slider::SnapToMark( float value )
   float closestDist = std::numeric_limits<float>::max();
 
   float mark;
-  for( std::size_t i = 0; i < mMarks.Size(); ++i)
+  for( MarkList::SizeType  i = 0; i < mMarks.Count(); ++i)
   {
     const Property::Value& propertyValue = mMarks[i];
     propertyValue.Get( mark );
index bd96f77..2250801 100644 (file)
@@ -31,12 +31,25 @@ using namespace Dali;
 
 namespace
 {
+/*
+ * Custom properties for where to put the actor.
+ *
+ * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild,
+ * the following custom properties of the actor are checked to decide the actor position inside the table
+ *
+ * These non-animatable properties should be registered to the child which would be added to the table
+ */
+const char * const CELL_INDEX_PROPERTY_NAME("cell-index");
+const char * const ROW_SPAN_PROPERTY_NAME("row-span");
+const char * const COLUMN_SPAN_PROPERTY_NAME("column-span");
+const char * const CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME("cell-horizontal-alignment");
+const char * const CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME("cell-vertical-alignment");
 
 /**
  * @brief Should the tableview fit around the given actor
  *
  * @param[in] actor The child actor to test against
- * @param[dimension] The dimnesion to test against
+ * @param[dimension] The dimension to test against
  */
 bool FitToChild( Actor actor, Dimension::Type dimension )
 {
@@ -49,7 +62,9 @@ bool FitToChild( Actor actor, Dimension::Type dimension )
 
 #define TABLEVIEW_TAG "DALI Toolkit::TableView "
 #define TV_LOG(fmt, args...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
+//#define TABLEVIEW_DEBUG 1
 
+#if defined(TABLEVIEW_DEBUG)
 void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
 {
   TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
@@ -101,6 +116,7 @@ void PrintVector( std::vector<float>& array )
   }
   TV_LOG( "\n" );
 }
+#endif // defined(TABLEVIEW_DEBUG)
 #endif // defined(DEBUG_ENABLED)
 
 } // namespace
@@ -134,15 +150,31 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layout-columns", MAP,
 
 DALI_TYPE_REGISTRATION_END()
 
-const Scripting::StringEnum< Toolkit::TableView::LayoutPolicy > LAYOUT_POLICY_STRING_TABLE[] =
+const Scripting::StringEnum LAYOUT_POLICY_STRING_TABLE[] =
 {
  { "fixed",    Toolkit::TableView::FIXED    },
  { "relative", Toolkit::TableView::RELATIVE },
- { "fill",     Toolkit::TableView::FILL     }
+ { "fill",     Toolkit::TableView::FILL     },
+ { "fit",      Toolkit::TableView::FIT      }
 };
-
 const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
 
+const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
+{
+  {"left",   HorizontalAlignment::LEFT},
+  {"center", HorizontalAlignment::CENTER},
+  {"right",  HorizontalAlignment::RIGHT}
+};
+const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(HORIZONTAL_ALIGNMENT_STRING_TABLE) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
+
+const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
+{
+  {"top",    VerticalAlignment::TOP},
+  {"center", VerticalAlignment::CENTER},
+  {"bottom", VerticalAlignment::BOTTOM}
+};
+const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(VERTICAL_ALIGNMENT_STRING_TABLE) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
+
 } // Unnamed namespace
 
 Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
@@ -166,10 +198,7 @@ bool TableView::AddChild( Actor& child, const Toolkit::TableView::CellPosition&
   DALI_ASSERT_ALWAYS( child );
 
   // if child is already parented, we adopt it
-  if( child.GetParent() )
-  {
-    child.GetParent().Remove( child );
-  }
+  child.Unparent();
 
   // check if we need to expand our data array
   if( position.rowIndex >= mCellData.GetRows() )
@@ -541,44 +570,44 @@ Size TableView::GetCellPadding()
   return mPadding;
 }
 
-void TableView::SetRowPolicy( unsigned int rowIndex, CellSizePolicy policy )
+void TableView::SetFitHeight( unsigned int rowIndex )
 {
   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
 
-  if( mRowData[ rowIndex ].sizePolicy != policy )
+  if( mRowData[ rowIndex ].sizePolicy != Toolkit::TableView::FIT )
   {
-    mRowData[ rowIndex ].sizePolicy = policy;
+    mRowData[ rowIndex ].sizePolicy = Toolkit::TableView::FIT;
 
     mRowColumnDirty = true;
     RelayoutRequest();
   }
 }
 
-TableView::CellSizePolicy TableView::GetRowPolicy( unsigned int rowIndex ) const
+bool TableView::IsFitHeight( unsigned int rowIndex ) const
 {
   DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
 
-  return mRowData[ rowIndex ].sizePolicy;
+  return mRowData[ rowIndex ].sizePolicy == Toolkit::TableView::FIT;
 }
 
-void TableView::SetColumnPolicy( unsigned int columnIndex, CellSizePolicy policy )
+void TableView::SetFitWidth( unsigned int columnIndex )
 {
   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
 
-  if( mColumnData[ columnIndex ].sizePolicy != policy )
+  if( mColumnData[ columnIndex ].sizePolicy != Toolkit::TableView::FIT )
   {
-    mColumnData[ columnIndex ].sizePolicy = policy;
+    mColumnData[ columnIndex ].sizePolicy = Toolkit::TableView::FIT;
 
     mRowColumnDirty = true;
     RelayoutRequest();
   }
 }
 
-TableView::CellSizePolicy TableView::GetColumnPolicy( unsigned int columnIndex ) const
+bool TableView::IsFitWidth( unsigned int columnIndex ) const
 {
   DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
 
-  return mColumnData[ columnIndex ].sizePolicy;
+  return mColumnData[ columnIndex ].sizePolicy == Toolkit::TableView::FIT;
 }
 
 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
@@ -587,7 +616,7 @@ void TableView::SetFixedHeight( unsigned int rowIndex, float height )
 
   RowColumnData& data = mRowData[ rowIndex ];
   data.size = height;
-  data.sizePolicy = FIXED;
+  data.sizePolicy = Toolkit::TableView::FIXED;
 
   mRowColumnDirty = true;
   RelayoutRequest();
@@ -606,7 +635,7 @@ void TableView::SetFixedWidth( unsigned int columnIndex, float width )
 
   RowColumnData& data = mColumnData[ columnIndex ];
   data.size = width;
-  data.sizePolicy = FIXED;
+  data.sizePolicy = Toolkit::TableView::FIXED;
 
   mRowColumnDirty = true;
   RelayoutRequest();
@@ -625,8 +654,7 @@ void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage
 
   RowColumnData& data = mRowData[ rowIndex ];
   data.fillRatio = heightPercentage;
-  data.userFillRatio = true;
-  data.sizePolicy = FILL;
+  data.sizePolicy = Toolkit::TableView::RELATIVE;
 
   mRowColumnDirty = true;
   RelayoutRequest();
@@ -645,8 +673,7 @@ void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentag
 
   RowColumnData& data = mColumnData[ columnIndex ];
   data.fillRatio = widthPercentage;
-  data.userFillRatio = true;
-  data.sizePolicy = FILL;
+  data.sizePolicy = Toolkit::TableView::RELATIVE;
 
   mRowColumnDirty = true;
   RelayoutRequest();
@@ -720,45 +747,89 @@ void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
 {
   CalculateRowColumnData();
 
-  // Go through the layout data
-  float cumulatedHeight = 0.0f;
-
-  const unsigned int rowCount = mCellData.GetRows();
+  // update every column position in ColumnData array
+  float cumulatedWidth = 0.0f;
   const unsigned int columnCount = mCellData.GetColumns();
+  for( unsigned int column = 0; column < columnCount; ++column )
+  {
+    mColumnData[column].position = cumulatedWidth;
+    cumulatedWidth += mColumnData[ column ].size;
+  }
 
+  // update every row position in RowData array
+  float cumulatedHeight = 0.0f;
+  const unsigned int rowCount = mCellData.GetRows();
   for( unsigned int row = 0; row < rowCount; ++row )
   {
-    float cumulatedWidth = 0.0f;
+    mRowData[row].position = cumulatedHeight;
+    cumulatedHeight += mRowData[ row ].size;
+  }
 
+  // Go through the layout data
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
     for( unsigned int column = 0; column < columnCount; ++column )
     {
-      Actor& actor = mCellData[ row ][ column ].actor;
-      const Toolkit::TableView::CellPosition position = mCellData[ row ][ column ].position;
+      CellData& cellData= mCellData[ row ][ column ];
+      Actor& actor = cellData.actor;
+      const Toolkit::TableView::CellPosition position = cellData.position;
 
       // If there is an actor and this is the main cell of the actor.
-      // An actor can be in multiple cells if its row or columnspan is more than 1.
+      // An actor can be in multiple cells if its row or column span is more than 1.
       // We however must lay out each actor only once.
-      if( actor && ( position.rowIndex == row ) && ( position.columnIndex == column ) )
+      if( actor &&  position.rowIndex == row && position.columnIndex == column )
       {
-        // Anchor actor to top left of table view
+        // Anchor actor to top left of the cell
         actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
         actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
 
+        Vector2( actor.GetRelayoutSize( Dimension::WIDTH ), actor.GetRelayoutSize( Dimension::HEIGHT ) );
+
         Padding padding;
         actor.GetPadding( padding );
 
-        Vector3 actorPosition( cumulatedWidth + mPadding.width + padding.left,       // Left padding
-                               cumulatedHeight + mPadding.height + padding.top,      // Top padding
-                               0.0f );
-        actor.SetPosition( actorPosition );
-      }
+        if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
+        {
+          actor.SetX( mColumnData[column].position + mPadding.width + padding.left );
+        }
+        else
+        {
+          float cellRightPosition = column+position.columnSpan < columnCount ? mColumnData[column+position.columnSpan].position : cumulatedWidth;
 
-      DALI_ASSERT_DEBUG( column < mColumnData.Size() );
-      cumulatedWidth += mColumnData[ column ].size;
-    }
+          if( cellData.horizontalAlignment ==  HorizontalAlignment::RIGHT )
+          {
+            actor.SetX( cellRightPosition - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
+          }
+          else //if( cellData.horizontalAlignment ==  HorizontalAlignment::CENTER )
+          {
+            actor.SetX( (mColumnData[column].position + cellRightPosition
+                       + padding.left - padding.right
+                       - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
+          }
+        }
 
-    DALI_ASSERT_DEBUG( row < mRowData.Size() );
-    cumulatedHeight += mRowData[ row ].size;
+        if( cellData.verticalAlignment == VerticalAlignment::TOP )
+        {
+          actor.SetY( mRowData[row].position + mPadding.height + padding.top );
+        }
+        else
+        {
+          float cellBottomPosition = row+position.rowSpan < rowCount ? mRowData[row+position.rowSpan].position : cumulatedHeight;
+
+          if( cellData.verticalAlignment == VerticalAlignment::BOTTOM )
+
+          {
+            actor.SetY( cellBottomPosition - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
+          }
+          else //if( cellData.verticalAlignment = VerticalAlignment::CENTER )
+          {
+            actor.SetY( (mRowData[row].position + cellBottomPosition
+                       + padding.top - padding.bottom
+                       - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
+          }
+        }
+      }
+    }
   }
 }
 
@@ -804,12 +875,12 @@ void TableView::SetProperty( BaseObject* object, Property::Index index, const Pr
       }
       case Toolkit::TableView::Property::LAYOUT_ROWS:
       {
-        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, value );
+        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value );
         break;
       }
       case Toolkit::TableView::Property::LAYOUT_COLUMNS:
       {
-        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, value );
+        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value );
         break;
       }
     }
@@ -866,29 +937,49 @@ void TableView::OnControlChildAdd( Actor& child )
     return;
   }
 
-  RelayoutRequest();
-
   // Test properties on actor
+  HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
+  VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
+  if( child.GetPropertyIndex( CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
+  {
+    std::string value = child.GetProperty( child.GetPropertyIndex(CELL_HORIZONTAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
+    Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
+                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                            HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                            horizontalAlignment );
+  }
+  if( child.GetPropertyIndex( CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME ) != Property::INVALID_INDEX )
+  {
+    std::string value = child.GetProperty( child.GetPropertyIndex(CELL_VERTICAL_ALIGNMENT_PROPERTY_NAME) ).Get<std::string >();
+    Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
+                                                          VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                          VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                          verticalAlignment );
+  }
+
+
   Toolkit::TableView::CellPosition cellPosition;
-  if( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
+  if( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
   {
-    cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
+    cellPosition.rowSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(ROW_SPAN_PROPERTY_NAME) ).Get<float>() );
   }
 
-  if( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
+  if( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) != Property::INVALID_INDEX )
   {
-    cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
+    cellPosition.columnSpan = static_cast<unsigned int>( child.GetProperty( child.GetPropertyIndex(COLUMN_SPAN_PROPERTY_NAME) ).Get<float>() );
   }
 
-  if( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) != Property::INVALID_INDEX )
+  if( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) != Property::INVALID_INDEX )
   {
-    Vector2 indices = child.GetProperty( child.GetPropertyIndex(Toolkit::TableView::CELL_INDICES_PROPERTY_NAME) ).Get<Vector2 >();
+    Vector2 indices = child.GetProperty( child.GetPropertyIndex(CELL_INDEX_PROPERTY_NAME) ).Get<Vector2 >();
     cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
     cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
 
     AddChild( child, cellPosition );
+    SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
 
     // Do not continue
+    RelayoutRequest();
     return;
   }
 
@@ -906,9 +997,12 @@ void TableView::OnControlChildAdd( Actor& child )
         data.actor = child;
         data.position.columnIndex = column;
         data.position.rowIndex = row;
+        data.horizontalAlignment = horizontalAlignment;
+        data.verticalAlignment = verticalAlignment;
         mCellData[ row ][ column ] = data;
 
         // Don't continue
+        RelayoutRequest();
         return;
       }
     }
@@ -923,7 +1017,10 @@ void TableView::OnControlChildAdd( Actor& child )
   data.actor = child;
   data.position.rowIndex = rowCount;
   data.position.columnIndex = 0;
+  data.horizontalAlignment = horizontalAlignment;
+  data.verticalAlignment = verticalAlignment;
   mCellData[ rowCount ][ 0 ] = data;
+  RelayoutRequest();
 }
 
 void TableView::OnControlChildRemove( Actor& child )
@@ -1045,29 +1142,46 @@ bool TableView::RemoveAllInstances( const Actor& child )
 void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
                                          void(TableView::*funcFixed)(unsigned int, float),
                                          void(TableView::*funcRelative)(unsigned int, float),
+                                         void(TableView::*funcFit)(unsigned int),
                                          const Property::Value& value )
 {
-  if( Property::MAP == value.GetType() )
+  Property::Map* map = value.GetMap();
+  if( map )
   {
-    Property::Map map = value.Get<Property::Map>();
-    unsigned int rowIndex(0);
-    for ( unsigned int i = 0, count = map.Count(); i < count; ++i )
+    unsigned int index(0);
+    for ( unsigned int i = 0, count = map->Count(); i < count; ++i )
     {
-      Property::Value& item = map.GetValue(i);
+      Property::Value& item = map->GetValue(i);
+      Property::Map* childMap = item.GetMap();
 
-      if( std::istringstream(map.GetKey(i)) >> rowIndex  // the key is a number
-          && Property::MAP == item.GetType())
+      std::istringstream( map->GetKey(i) ) >> index;
+      if( childMap )
       {
-        if( item.HasKey( "policy" ) && item.HasKey( "value" ) )
+        Property::Value* policy = childMap->Find( "policy" );
+        Property::Value* value = childMap->Find( "value" );
+        if( policy && value )
         {
-          Toolkit::TableView::LayoutPolicy policy = Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( item.GetValue("policy").Get<std::string>().c_str(), LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT );
-          if( policy == Toolkit::TableView::FIXED )
+          std::string policyValue;
+          policy->Get( policyValue );
+          Toolkit::TableView::LayoutPolicy policy;
+          if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(),
+                                                                             LAYOUT_POLICY_STRING_TABLE,
+                                                                             LAYOUT_POLICY_STRING_TABLE_COUNT,
+                                                                             policy ) )
           {
-            (tableViewImpl.*funcFixed)( rowIndex, item.GetValue("value").Get<float>() );
-          }
-          else if( policy == Toolkit::TableView::RELATIVE )
-          {
-            (tableViewImpl.*funcRelative)( rowIndex, item.GetValue("value").Get<float>() );
+            if( policy == Toolkit::TableView::FIXED  )
+            {
+              (tableViewImpl.*funcFixed)( index, value->Get<float>() );
+            }
+            else if( policy == Toolkit::TableView::RELATIVE )
+            {
+              (tableViewImpl.*funcRelative)( index, value->Get<float>() );
+            }
+            else if( policy == Toolkit::TableView::FIT )
+            {
+              (tableViewImpl.*funcFit)( index );
+            }
+            // do nothing for FILL policy
           }
         }
       }
@@ -1091,49 +1205,56 @@ Property::Value TableView::GetColumnWidthsPropertyValue()
 
 void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
 {
-  std::string fixedPolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
-  std::string relativePolicy( Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE, LAYOUT_POLICY_STRING_TABLE, LAYOUT_POLICY_STRING_TABLE_COUNT ) );
+  const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED,
+                                                                                               LAYOUT_POLICY_STRING_TABLE,
+                                                                                               LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE,
+                                                                                                  LAYOUT_POLICY_STRING_TABLE,
+                                                                                                  LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL,
+                                                                                              LAYOUT_POLICY_STRING_TABLE,
+                                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT,
+                                                                                             LAYOUT_POLICY_STRING_TABLE,
+                                                                                             LAYOUT_POLICY_STRING_TABLE_COUNT );
 
   const RowColumnArray::SizeType count = data.Size();
   for( RowColumnArray::SizeType i = 0; i < count; i++ )
   {
     const RowColumnData& dataInstance = data[ i ];
 
+    Property::Map item;
     switch( dataInstance.sizePolicy )
     {
-      case FIXED:
+      case Toolkit::TableView::FIXED:
       {
-        Property::Map item;
         item[ "policy" ] = fixedPolicy;
         item[ "value" ] = dataInstance.size;
-
-        std::ostringstream ss;
-        ss << i;
-
-        map[ ss.str() ] = item;
-
         break;
       }
-
-      case FILL:
+      case Toolkit::TableView::RELATIVE:
       {
-        Property::Map item;
         item[ "policy" ] = relativePolicy;
         item[ "value" ] = dataInstance.fillRatio;
-
-        std::ostringstream ss;
-        ss << i;
-
-        map[ ss.str() ] = item;
-
         break;
       }
-
+      case Toolkit::TableView::FIT:
+      {
+        item[ "policy" ] = fitPolicy;
+        item[ "value" ] = 0.f;
+        break;
+      }
+      case Toolkit::TableView::FILL:
       default:
       {
+        item[ "policy" ] = fillPolicy;
+        item[ "value" ] = 0.f;
         break;
       }
     }
+    std::ostringstream ss;
+    ss << i;
+    map[ ss.str() ] = item;
   }
 }
 
@@ -1291,7 +1412,7 @@ float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimensi
               }
 
               // Apply padding
-              cellSize -= mPadding.width * 2.0f;
+              cellSize -= mPadding.height * 2.0f;
               if( cellSize < 0.0f )
               {
                 cellSize = 0.0f;
@@ -1356,16 +1477,13 @@ void TableView::ComputeRelativeSizes( RowColumnArray& data )
   {
     RowColumnData& dataInstance = data[ i ];
 
-    if( dataInstance.sizePolicy == FILL )
+    if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
     {
-      if( dataInstance.userFillRatio )
-      {
-        relativeTotal += dataInstance.fillRatio;
-      }
-      else
-      {
-        fillData.PushBack( &dataInstance );
-      }
+      relativeTotal += dataInstance.fillRatio;
+    }
+    else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
+    {
+      fillData.PushBack( &dataInstance );
     }
   }
 
@@ -1399,8 +1517,9 @@ float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
 
     switch( dataInstance.sizePolicy )
     {
-      case FIXED:
-      case FIT:
+      // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row
+      case Toolkit::TableView::FIXED:
+      case Toolkit::TableView::FIT:
       {
         totalSize += dataInstance.size;
         break;
@@ -1447,7 +1566,7 @@ void TableView::CalculateFixedSizes( RowColumnArray& data, Dimension::Type dimen
   {
     RowColumnData& dataInstance = data[ i ];
 
-    if( dataInstance.sizePolicy == FIT )
+    if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
     {
       // Find the size of the biggest actor in the row or column
       float maxActorHeight = 0.0f;
@@ -1485,7 +1604,7 @@ void TableView::CalculateRelativeSizes( RowColumnArray& data, float size )
   {
     RowColumnData& dataInstance = data[ i ];
 
-    if( dataInstance.sizePolicy == FILL )
+    if( dataInstance.sizePolicy == Toolkit::TableView::FILL ||  dataInstance.sizePolicy == Toolkit::TableView::RELATIVE)
     {
       dataInstance.size = dataInstance.fillRatio * size;
     }
@@ -1496,7 +1615,7 @@ bool TableView::FindFit( const RowColumnArray& data )
 {
   for( unsigned int i = 0, count = data.Size(); i < count; ++i )
   {
-    if( data[ i ].sizePolicy == FIT )
+    if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
     {
       return true;
     }
index d1d8aef..62e0a6f 100644 (file)
@@ -41,16 +41,6 @@ class TableView : public Control
 public:
 
   /**
-   * Enum for the size policies of rows and columns
-   */
-  enum CellSizePolicy
-  {
-    FILL,       ///< Fill up available space, may have a ratio associated with it
-    FIXED,      ///< A specific fixed width or height
-    FIT         ///< Fit around actors in the row or column
-  };
-
-  /**
    * Create a new TableView.
    * @return A smart-pointer to the newly allocated TableView.
    */
@@ -127,36 +117,24 @@ public:
   Size GetCellPadding();
 
   /**
-   * @brief Set a row policy
-   *
-   * @param[in] rowIndex The row to set the policy for
-   * @param[in] policy The policy to set
+   * @copydoc Toolkit::TableView::SetFitHeight
    */
-  void SetRowPolicy( unsigned int rowIndex, CellSizePolicy policy );
+  void SetFitHeight( unsigned int rowIndex );
 
   /**
-   * @brief Querry a row policy
-   *
-   * @param[in] rowIndex The row to querry
-   * @return Return the policy
+   * @copydoc Toolkit::TableView::IsFitHeight
    */
-  CellSizePolicy GetRowPolicy( unsigned int rowIndex ) const;
+  bool IsFitHeight( unsigned int rowIndex ) const;
 
   /**
-   * @brief Set a column policy
-   *
-   * @param[in] columnIndex The column to set the policy for
-   * @param[in] policy The policy to set
+   * @copydoc Toolkit::TableView::SetFitWidth
    */
-  void SetColumnPolicy( unsigned int columnIndex, CellSizePolicy policy );
+  void SetFitWidth( unsigned int columnIndex );
 
   /**
-   * @brief Querry a column policy
-   *
-   * @param[in] columnIndex The column to querry
-   * @return Return the policy
+   * @copydoc Toolkit::TableView::IsFitWidth
    */
-  CellSizePolicy GetColumnPolicy( unsigned int columnIndex ) const;
+  bool IsFitWidth( unsigned int columnIndex ) const;
 
   /**
    * @copydoc Toolkit::TableView::SetFixedWidth
@@ -299,8 +277,8 @@ private: // Implementation
     RowColumnData()
     : size( 0.0f ),
       fillRatio( 0.0f ),
-      sizePolicy( FILL ),
-      userFillRatio( false )
+      position(0.0f),
+      sizePolicy( Toolkit::TableView::FILL )
     {
     }
 
@@ -310,18 +288,18 @@ private: // Implementation
      * @param[in] newSize The size to set for this data
      * @param[in] newSizePolicy The policy used to interpret the size value
      */
-    RowColumnData( float newSize, float newFillRatio, CellSizePolicy newSizePolicy, bool newUserFillRatio )
+    RowColumnData( float newSize, float newFillRatio, Toolkit::TableView::LayoutPolicy newSizePolicy )
     : size( newSize ),
       fillRatio( newFillRatio ),
-      sizePolicy( newSizePolicy ),
-      userFillRatio( newUserFillRatio )
+      position(0.0f),
+      sizePolicy( newSizePolicy )
     {
     }
 
-    float size;                       ///< Set or calculated size
-    float fillRatio;                  ///< Ratio to fill remaining space
-    CellSizePolicy sizePolicy;        ///< The size policy used to interpret the size value
-    bool userFillRatio : 1;           ///< FillRatio was set by user
+    float size;                                  ///< Set or calculated size
+    float fillRatio;                             ///< Ratio to fill remaining space, only valid with RELATIVE or FILL policy
+    float position;                              ///< Position of the row/column, this value is updated during every Relayout round
+    Toolkit::TableView::LayoutPolicy sizePolicy; ///< The size policy used to interpret the size value
   };
 
   typedef Dali::Vector<RowColumnData> RowColumnArray;
@@ -447,13 +425,15 @@ private: // scripting support
   /**
    * Called to set the heights/widths property.
    * @param[in] tableViewImpl The object whose property is set.
-   * @param[in] funcFixed The set function to call, it can be SetFixedHeight or SetFixedWidths.
-   * @param[in] funcRelative The set function to call, it can be SetRelativeHeight or SetRelativeWidths.
+   * @param[in] funcFixed The set function to call, it can be SetFixedHeight or SetFixedWidth.
+   * @param[in] funcRelative The set function to call, it can be SetRelativeHeight or SetRelativeWidth.
+   * @param[in] funcFit The set function to call, it can be SetFitHeight or SetFiltWidth.
    * @param[in] value The new property value.
    */
   static void SetHeightOrWidthProperty( TableView& tableViewImpl,
                                         void(TableView::*funcFixed)(unsigned int, float),
                                         void(TableView::*funcRelative)(unsigned int, float),
+                                        void(TableView::*funcFit)(unsigned int),
                                         const Property::Value& map );
 
   /**
@@ -518,7 +498,7 @@ private:
 
 private: // Data
 
-  Array2d<CellData> mCellData;                ///< Data for each cell: Actor, alignment settings etc
+  Array2d<CellData> mCellData;   ///< Data for each cell: Actor, alignment settings etc
 
   RowColumnArray mRowData;       ///< Data for each row
   RowColumnArray mColumnData;    ///< Data for each column
@@ -526,7 +506,7 @@ private: // Data
 
   Size mPadding;                 ///< Padding to apply to each cell
   bool mLayoutingChild;          ///< Can't be a bitfield due to Relayouting lock
-  bool mRowColumnDirty : 1;       ///< Flag to indicate the row column data is dirty
+  bool mRowColumnDirty : 1;      ///< Flag to indicate the row column data is dirty
 };
 
 } // namespace Internal
index c687f9e..ce6e9f0 100644 (file)
@@ -62,7 +62,7 @@ namespace // unnamed namespace
 namespace
 {
 
-const Scripting::StringEnum< Toolkit::Text::LayoutEngine::HorizontalAlignment > HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
+const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
 {
   { "BEGIN",  Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN  },
   { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER },
@@ -70,7 +70,7 @@ const Scripting::StringEnum< Toolkit::Text::LayoutEngine::HorizontalAlignment >
 };
 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
 
-const Scripting::StringEnum< Toolkit::Text::LayoutEngine::VerticalAlignment > VERTICAL_ALIGNMENT_STRING_TABLE[] =
+const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
 {
   { "TOP",    Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_TOP    },
   { "CENTER", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_CENTER },
@@ -251,11 +251,14 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
           const std::string alignStr = value.Get< std::string >();
           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
 
-          const LayoutEngine::HorizontalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::HorizontalAlignment >( alignStr.c_str(),
-                                                                                                                        HORIZONTAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                        HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
-
-          impl.mController->SetHorizontalAlignment( alignment );
+          LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN );
+          if( Scripting::GetEnumeration< LayoutEngine::HorizontalAlignment >( alignStr.c_str(),
+                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                                              alignment ) )
+          {
+            impl.mController->SetHorizontalAlignment( alignment );
+          }
         }
         break;
       }
@@ -266,11 +269,14 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
           const std::string alignStr = value.Get< std::string >();
           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %f\n", impl.mController.Get(), alignStr.c_str() );
 
-          LayoutEngine::VerticalAlignment alignment = Scripting::GetEnumeration< LayoutEngine::VerticalAlignment >( alignStr.c_str(),
-                                                                                                                    VERTICAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                    VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
-
-          impl.mController->SetVerticalAlignment( alignment );
+          LayoutEngine::VerticalAlignment alignment( LayoutEngine::VERTICAL_ALIGN_BOTTOM );
+          if( Scripting::GetEnumeration< LayoutEngine::VerticalAlignment >( alignStr.c_str(),
+                                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                                            alignment ) )
+          {
+            impl.mController->SetVerticalAlignment( alignment );
+          }
         }
         break;
       }
@@ -612,9 +618,13 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mController )
         {
-          value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(),
-                                                                                                                  HORIZONTAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                  HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ) );
+          const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetLayoutEngine().GetHorizontalAlignment(),
+                                                                                                                HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                                                                                HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
+          if( name )
+          {
+            value = std::string( name );
+          }
         }
         break;
       }
@@ -622,9 +632,13 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mController )
         {
-          value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetLayoutEngine().GetVerticalAlignment(),
-                                                                                                                  VERTICAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                  VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ) );
+          const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetLayoutEngine().GetVerticalAlignment(),
+                                                                                                              VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                                                                              VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
+          if( name )
+          {
+            value = std::string( name );
+          }
         }
         break;
       }
@@ -859,7 +873,8 @@ void TextField::OnInitialize()
 
   mController = Text::Controller::New( *this );
 
-  mDecorator = Text::Decorator::New( *this, *mController );
+  mDecorator = Text::Decorator::New( *mController,
+                                     *mController );
 
   mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
 
@@ -951,6 +966,24 @@ void TextField::RenderText()
     {
       Self().Add( mRenderableActor );
     }
+
+    for( std::vector<Actor>::const_iterator it = mClippingDecorationActors.begin(),
+           endIt = mClippingDecorationActors.end();
+         it != endIt;
+         ++it )
+    {
+      Actor actor = *it;
+
+      if( mClipper )
+      {
+        mClipper->GetRootActor().Add( actor );
+      }
+      else
+      {
+        Self().Add( actor );
+      }
+    }
+    mClippingDecorationActors.clear();
   }
 }
 
@@ -1036,10 +1069,19 @@ bool TextField::OnKeyEvent( const KeyEvent& event )
   return mController->KeyEvent( event );
 }
 
-ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+void TextField::AddDecoration( Actor& actor, bool needsClipping )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
-  return mController->OnImfEvent( imfManager, imfEvent );
+  if( actor )
+  {
+    if( needsClipping )
+    {
+      mClippingDecorationActors.push_back( actor );
+    }
+    else
+    {
+      Self().Add( actor );
+    }
+  }
 }
 
 void TextField::RequestTextRelayout()
@@ -1071,6 +1113,12 @@ void TextField::MaxLengthReached()
   mMaxLengthReachedSignal.Emit( handle );
 }
 
+ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
+  return mController->OnImfEvent( imfManager, imfEvent );
+}
+
 void TextField::EnableClipping( bool clipping, const Vector2& size )
 {
   if( clipping )
index 6fdab15..a305880 100644 (file)
@@ -147,9 +147,9 @@ private: // From Control
   virtual bool OnKeyEvent(const KeyEvent& event);
 
   /**
-   * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent)
+   * @copydoc Text::ControlInterface::AddDecoration()
    */
-  ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
 
   /**
    * @copydoc Text::ControlInterface::RequestTextRelayout()
@@ -166,6 +166,11 @@ private: // From Control
    */
   virtual void MaxLengthReached();
 
+  /**
+   * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent)
+   */
+  ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
+
 private: // Implementation
 
   /**
@@ -223,6 +228,7 @@ private: // Data
   Text::RendererPtr mRenderer;
   Text::DecoratorPtr mDecorator;
   Text::ClipperPtr mClipper; ///< For EXCEED_POLICY_CLIP
+  std::vector<Actor> mClippingDecorationActors;   ///< Decoration actors which need clipping.
 
   Actor mRenderableActor;
 
index d4b5171..4bbadfb 100644 (file)
@@ -50,7 +50,7 @@ namespace
 namespace
 {
 
-const Scripting::StringEnum< Toolkit::Text::LayoutEngine::HorizontalAlignment > HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
+const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
 {
   { "BEGIN",  Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_BEGIN  },
   { "CENTER", Toolkit::Text::LayoutEngine::HORIZONTAL_ALIGN_CENTER },
@@ -58,7 +58,7 @@ const Scripting::StringEnum< Toolkit::Text::LayoutEngine::HorizontalAlignment >
 };
 const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE ) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
 
-const Scripting::StringEnum< Toolkit::Text::LayoutEngine::VerticalAlignment > VERTICAL_ALIGNMENT_STRING_TABLE[] =
+const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
 {
   { "TOP",    Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_TOP    },
   { "CENTER", Toolkit::Text::LayoutEngine::VERTICAL_ALIGN_CENTER },
@@ -189,11 +189,14 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
       {
         if( impl.mController )
         {
-          const LayoutEngine::HorizontalAlignment alignment = Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
-                                                                                                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
-
-          impl.mController->SetHorizontalAlignment( alignment );
+          LayoutEngine::HorizontalAlignment alignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN );
+          if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::HorizontalAlignment >( value.Get< std::string >().c_str(),
+                                                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                                                             HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                                                             alignment ) )
+          {
+            impl.mController->SetHorizontalAlignment( alignment );
+          }
         }
         break;
       }
@@ -201,11 +204,14 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
       {
         if( impl.mController )
         {
-          const LayoutEngine::VerticalAlignment alignment = Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
-                                                                                                                                         VERTICAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                                         VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
-
-          impl.mController->SetVerticalAlignment( alignment );
+          LayoutEngine::VerticalAlignment alignment( LayoutEngine::VERTICAL_ALIGN_BOTTOM );
+          if( Scripting::GetEnumeration< Toolkit::Text::LayoutEngine::VerticalAlignment >( value.Get< std::string >().c_str(),
+                                                                                           VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                                                           VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                                                           alignment ) )
+          {
+            impl.mController->SetVerticalAlignment( alignment );
+          }
         }
         break;
       }
@@ -356,9 +362,13 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mController )
         {
-          value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
-                                                                                                                  HORIZONTAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                  HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT ) );
+          const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::HorizontalAlignment >( impl.mController->GetHorizontalAlignment(),
+                                                                                                                HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                                                                                HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
+          if( name )
+          {
+            value = std::string( name );
+          }
         }
         break;
       }
@@ -366,9 +376,13 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mController )
         {
-          value = std::string( Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
-                                                                                                                VERTICAL_ALIGNMENT_STRING_TABLE,
-                                                                                                                VERTICAL_ALIGNMENT_STRING_TABLE_COUNT ) );
+          const char* name = Scripting::GetEnumerationName< Toolkit::Text::LayoutEngine::VerticalAlignment >( impl.mController->GetVerticalAlignment(),
+                                                                                                              VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                                                                              VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
+          if( name )
+          {
+            value = std::string( name );
+          }
         }
         break;
       }
@@ -510,6 +524,11 @@ void TextLabel::OnStageConnect( Dali::Actor actor )
   }
 }
 
+void TextLabel::AddDecoration( Actor& actor, bool needsClipping )
+{
+  // TextLabel does not show decorations
+}
+
 void TextLabel::OnStageConnection( unsigned int depth )
 {
   mDepth = depth;
index 37e531c..0984475 100644 (file)
@@ -93,6 +93,11 @@ private: // From Control
   virtual float GetHeightForWidth( float width );
 
   /**
+   * @copydoc Text::ControlInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
+
+  /**
    * @copydoc Control::OnStageConnection()
    */
   virtual void OnStageConnection( unsigned int depth );
index e2ee154..e0d6435 100644 (file)
@@ -19,7 +19,7 @@
 #include <dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/buttons/push-button.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
 #include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
 #include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/vector4.h>
+#include <dali/devel-api/object/type-registry-helper.h>
 #include <libintl.h>
 #include <cfloat>
 
-// todo Move this to adaptor??
-#define GET_LOCALE_TEXT(string) dgettext("elementary", string)
-
 namespace Dali
 {
 
@@ -46,15 +44,14 @@ namespace Internal
 
 namespace
 {
-const Dali::Vector4 DEFAULT_POPUP_BACKGROUND( Dali::Vector4( .20f, 0.29f, 0.44f, 1.0f ) );
-const Dali::Vector4 DEFAULT_POPUP_BACKGROUND_PRESSED( Dali::Vector4( 0.07f, 0.10f, 0.17f, 1.0f ) );
-const Dali::Vector4 DEFAULT_POPUP_LINE_COLOR( Dali::Vector4( 0.36f, 0.45f, 0.59f, 1.0f ) );
+// todo Move this to adaptor??
+#define GET_LOCALE_TEXT(string) dgettext("elementary", string)
+
+const Dali::Vector4 DEFAULT_POPUP_LINE_COLOR( Dali::Vector4( 0.69f, 0.93f, 0.93f, 1.0f ) );
 const Dali::Vector4 DEFAULT_OPTION_ICON( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
-const Dali::Vector4 DEFAULT_OPTION_ICON_PRESSED( Dali::Vector4( 0.5f, 1.0f, 1.0f, 1.0f ) );
-const Dali::Vector4 DEFAULT_OPTION_TEXT( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
-const Dali::Vector4 DEFAULT_OPTION_TEXT_PRESSED( Dali::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
+const Dali::Vector4 DEFAULT_OPTION_ICON_PRESSED( Dali::Vector4( 0.12f, 0.56f, 1.0f, 1.0f ) );
 
-const std::string DEFAULT_POPUP_BACKGROUND_IMAGE( DALI_IMAGE_DIR "popup_bubble_bg.#.png" );
+const std::string DEFAULT_POPUP_BACKGROUND_IMAGE( DALI_IMAGE_DIR "selection-popup-bg#.png" );
 const std::string OPTION_ICON_CLIPBOARD( DALI_IMAGE_DIR "copy_paste_icon_clipboard.png" );
 const std::string OPTION_ICON_COPY( DALI_IMAGE_DIR "copy_paste_icon_copy.png" );
 const std::string OPTION_ICON_CUT( DALI_IMAGE_DIR "copy_paste_icon_cut.png" );
@@ -62,20 +59,27 @@ const std::string OPTION_ICON_PASTE( DALI_IMAGE_DIR "copy_paste_icon_paste.png"
 const std::string OPTION_ICON_SELECT( DALI_IMAGE_DIR "copy_paste_icon_select.png" );
 const std::string OPTION_ICON_SELECT_ALL( DALI_IMAGE_DIR "copy_paste_icon_select_all.png" );
 
-const Dali::Vector2 DEFAULT_POPUP_MAX_SIZE( 450.0f, 100.0f ); ///< The maximum size of the popup.
-
-const Dali::Vector2 OPTION_ICON_SIZE( 65.0f, 65.0f );       ///< The size of the icon.
 const float OPTION_MARGIN_WIDTH( 10.f );          ///< The margin between the right or lefts edge and the text or icon.
-const float OPTION_MAX_WIDTH( 110.0f );          ///< The maximum width of the option   //todo Make Property
-const float OPTION_MIN_WIDTH( 86.0f );           ///< The minimum width of the option. //todo Make Property
-const float POPUP_DIVIDER_WIDTH( 3.f );        ///< The size of the divider.
 
-const Dali::Vector2 POPUP_TAIL_SIZE( 20.0f, 16.0f ); ///< The size of the tail.
-const float POPUP_TAIL_Y_OFFSET( 5.f );        ///< The y offset of the tail (when its position is on the bottom).
-const float POPUP_TAIL_TOP_Y_OFFSET( 3.f );    ///< The y offset of the tail (when its position is on the top).
+#ifdef DGETTEXT_ENABLED
+
+#define POPUP_CUT_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CUT")
+#define POPUP_COPY_STRING GET_LOCALE_TEXT("IDS_COM_BODY_COPY")
+#define POPUP_PASTE_STRING GET_LOCALE_TEXT("IDS_COM_BODY_PASTE")
+#define POPUP_SELECT_STRING GET_LOCALE_TEXT("IDS_COM_SK_SELECT")
+#define POPUP_SELECT_ALL_STRING GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL")
+#define POPUP_CLIPBOARD_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD")
+
+#else
 
-const float HIDE_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup hide animation in seconds.
-const float SHOW_POPUP_ANIMATION_DURATION( 0.2f ); ///< Duration of popup show animation in seconds.
+#define POPUP_CUT_STRING  "Cut"
+#define POPUP_COPY_STRING  "Copy"
+#define POPUP_PASTE_STRING  "Paste"
+#define POPUP_SELECT_STRING  "Select"
+#define POPUP_SELECT_ALL_STRING  "Select All"
+#define POPUP_CLIPBOARD_STRING  "Clipboard"
+
+#endif
 
 const char* const OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
 const char* const OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
@@ -84,23 +88,43 @@ const char* const OPTION_COPY("option-copy");
 const char* const OPTION_PASTE("option-paste");                                    // "Paste" popup option.
 const char* const OPTION_CLIPBOARD("option-clipboard");                            // "Clipboard" popup option.
 
-} // namespace
+BaseHandle Create()
+{
+  return Toolkit::TextSelectionPopup::New( Toolkit::TextSelectionPopup::NONE, NULL );
+}
+
+// Setup properties, signals and actions using the type-registry.
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionPopup, Toolkit::Control, Create );
 
-//// Comparison function for ButtonRequirement Priority
-//bool TextSelectionPopup::PriorityCompare( ButtonRequirement const& a, ButtonRequirement const& b )
-//{
-//  return a.priority < b.priority;
-//}
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-max-size", VECTOR2,   POPUP_MAX_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-min-size", VECTOR2,   POPUP_MIN_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-max-size", VECTOR2,   OPTION_MAX_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-min-size", VECTOR2,   OPTION_MIN_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "option-divider-size", VECTOR2,   OPTION_DIVIDER_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-clipboard-button-image", STRING, POPUP_CLIPBOARD_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-cut-button-image", STRING, POPUP_CUT_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-copy-button-image", STRING, POPUP_COPY_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-paste-button-image", STRING, POPUP_PASTE_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-select-button-image", STRING, POPUP_SELECT_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popup-select-all-button-image", STRING, POPUP_SELECT_ALL_BUTTON_ICON_IMAGE )
 
+DALI_TYPE_REGISTRATION_END()
 
-Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New()
+} // namespace
+
+
+Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New( Toolkit::TextSelectionPopup::Buttons buttonsToEnable,
+                                                           TextSelectionPopupCallbackInterface* callbackInterface )
 {
-  // Create the implementation, temporarily owned by this handle on stack
-  IntrusivePtr< TextSelectionPopup > impl = new TextSelectionPopup();
+   // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextSelectionPopup > impl = new TextSelectionPopup( callbackInterface );
 
   // Pass ownership to CustomActor handle
   Dali::Toolkit::TextSelectionPopup handle( *impl );
 
+  impl->mEnabledButtons = buttonsToEnable;
+
   // Second-phase init of the implementation
   // This can only be done after the CustomActor connection has been made...
   impl->Initialize();
@@ -120,49 +144,63 @@ void TextSelectionPopup::SetProperty( BaseObject* object, Property::Index index,
     {
       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
       {
-       impl.SetPopupMaxSize( value.Get< Vector2 >() );
+       impl.SetDimensionToCustomise( POPUP_MAXIMUM_SIZE, value.Get< Vector2 >() );
        break;
       }
-      case Toolkit::TextSelectionPopup::Property::POPUP_BACKGROUND_IMAGE:
+      case Toolkit::TextSelectionPopup::Property::POPUP_MIN_SIZE:
       {
-        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_BACKGROUND, image );
+        impl.SetDimensionToCustomise( POPUP_MINIMUM_SIZE, value.Get< Vector2 >() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_MAXIMUM_SIZE, value.Get< Vector2 >() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_MINIMUM_SIZE, value.Get< Vector2>() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_DIVIDER_SIZE, value.Get< Vector2>() );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_CLIPBOARD_BUTTON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD, image );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_CUT_BUTTON_ICON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::CUT, image );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_COPY_BUTTON_ICON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::COPY, image );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_PASTE_BUTTON_ICON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::PASTE, image );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_SELECT_BUTTON_ICON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT, image );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
-        impl.SetPopupImage( POPUP_SELECT_ALL_BUTTON_ICON, image );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL, image );
         break;
       }
     } // switch
@@ -183,21 +221,27 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
     {
       case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
       {
-        value = impl.GetPopupMaxSize();
+        value = impl.GetDimensionToCustomise( POPUP_MAXIMUM_SIZE );
         break;
       }
-      case Toolkit::TextSelectionPopup::Property::POPUP_BACKGROUND_IMAGE:
+      case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_BACKGROUND ) );
-        if( image )
-        {
-          value = image.GetUrl();
-        }
+        value = impl.GetDimensionToCustomise( OPTION_MAXIMUM_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( OPTION_MINIMUM_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( OPTION_DIVIDER_SIZE );
         break;
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_CLIPBOARD_BUTTON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD ) );
         if( image )
         {
           value = image.GetUrl();
@@ -206,7 +250,7 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_CUT_BUTTON_ICON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CUT ) );
         if( image )
         {
           value = image.GetUrl();
@@ -215,7 +259,7 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_COPY_BUTTON_ICON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::COPY ) );
         if( image )
         {
           value = image.GetUrl();
@@ -224,7 +268,7 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_PASTE_BUTTON_ICON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::PASTE ) );
         if( image )
         {
           value = image.GetUrl();
@@ -233,7 +277,7 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_SELECT_BUTTON_ICON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT ) );
         if( image )
         {
           value = image.GetUrl();
@@ -242,7 +286,7 @@ Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::I
       }
       case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
       {
-        ResourceImage image = ResourceImage::DownCast( impl.GetPopupImage( POPUP_SELECT_ALL_BUTTON_ICON ) );
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL ) );
         if( image )
         {
           value = image.GetUrl();
@@ -259,106 +303,220 @@ void TextSelectionPopup::OnInitialize()
   CreatePopup();
 }
 
-void TextSelectionPopup::OnRelayout( const Vector2& size, RelayoutContainer& container )
+bool TextSelectionPopup::OnCutButtonPressed( Toolkit::Button button )
 {
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
+  }
 
+  return true;
 }
 
-void TextSelectionPopup::SetPopupMaxSize( const Size& maxSize )
+bool TextSelectionPopup::OnCopyButtonPressed( Toolkit::Button button )
 {
-  mMaxSize = maxSize;
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::COPY );
+  }
+
+  return true;
 }
 
-const Dali::Vector2& TextSelectionPopup::GetPopupMaxSize() const
+bool TextSelectionPopup::OnPasteButtonPressed( Toolkit::Button button )
 {
-  return mMaxSize;
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::PASTE );
+  }
+
+  return true;
 }
 
-void TextSelectionPopup::SetPopupImage( PopupParts part, Dali::Image image )
+bool TextSelectionPopup::OnSelectButtonPressed( Toolkit::Button button )
 {
-   switch ( part )
-   {
-   case POPUP_BACKGROUND :
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnSelectAllButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT_ALL );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnClipboardButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::CLIPBOARD );
+  }
+
+  return true;
+}
+
+void TextSelectionPopup::SetDimensionToCustomise( const PopupCustomisations& settingToCustomise, const Size& dimension )
+{
+  switch( settingToCustomise )
+  {
+    case POPUP_MAXIMUM_SIZE :
+    {
+      Actor self = Self();
+      mMaxSize = dimension;
+      if ( mToolbar )
+      {
+        mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, mMaxSize );
+      }
+      break;
+    }
+    case POPUP_MINIMUM_SIZE :
+    {
+      Actor self = Self();
+      mMinSize = dimension;
+      // Option can not be smaller than this if only one.
+      break;
+    }
+    case OPTION_MAXIMUM_SIZE :
+    {
+      mOptionMaxSize = dimension;
+      // Option max size not currently currently supported
+
+      break;
+    }
+    case OPTION_MINIMUM_SIZE :
+    {
+      mOptionMinSize = dimension;
+      // Option min size not currently currently supported
+      break;
+    }
+    case OPTION_DIVIDER_SIZE :
+    {
+      mOptionDividerSize = dimension;
+      if ( mToolbar )
+      {
+        // Resize Dividers not currently supported
+      }
+      break;
+    }
+  } // switch
+}
+
+Size TextSelectionPopup::GetDimensionToCustomise( const PopupCustomisations& settingToCustomise )
+{
+  switch( settingToCustomise )
+  {
+    case POPUP_MAXIMUM_SIZE :
+    {
+      return mMaxSize;
+    }
+    case POPUP_MINIMUM_SIZE :
+    {
+      return mMinSize;
+    }
+    case OPTION_MAXIMUM_SIZE :
+    {
+      return mOptionMaxSize;
+    }
+    case OPTION_MINIMUM_SIZE :
+    {
+      return mOptionMinSize;
+    }
+    case OPTION_DIVIDER_SIZE :
+    {
+      return mOptionDividerSize;
+    }
+  } // switch
+
+  return Size::ZERO;
+}
+
+void TextSelectionPopup::SetButtonImage( Toolkit::TextSelectionPopup::Buttons button, Dali::Image image )
+{
+   switch ( button )
    {
-     mBackgroundImage = image;
-   }
    break;
-   case POPUP_CLIPBOARD_BUTTON :
+   case Toolkit::TextSelectionPopup::CLIPBOARD:
    {
      mClipboardIconImage  = image;
    }
    break;
-   case POPUP_CUT_BUTTON_ICON :
+   case Toolkit::TextSelectionPopup::CUT :
    {
      mCutIconImage = image;
    }
    break;
-   case POPUP_COPY_BUTTON_ICON :
+   case Toolkit::TextSelectionPopup::COPY :
    {
      mCopyIconImage = image;
    }
    break;
-   case POPUP_PASTE_BUTTON_ICON :
+   case Toolkit::TextSelectionPopup::PASTE :
    {
      mPasteIconImage = image;
    }
    break;
-   case POPUP_SELECT_BUTTON_ICON :
+   case Toolkit::TextSelectionPopup::SELECT :
    {
      mSelectIconImage = image;
    }
    break;
-   case POPUP_SELECT_ALL_BUTTON_ICON :
+   case Toolkit::TextSelectionPopup::SELECT_ALL :
    {
      mSelectAllIconImage = image;
    }
    break;
-
+   default :
+   {
+     DALI_ASSERT_DEBUG( "TextSelectionPopup SetPopupImage Unknown Button" );
+   }
    } // switch
 }
 
-Dali::Image TextSelectionPopup::GetPopupImage( PopupParts part )
+Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::Buttons button )
 {
-  switch ( part )
+  switch ( button )
   {
-  case POPUP_BACKGROUND :
-  {
-    return mBackgroundImage;
-  }
-  break;
-  case POPUP_CLIPBOARD_BUTTON :
+  case Toolkit::TextSelectionPopup::CLIPBOARD :
   {
     return mClipboardIconImage;
   }
   break;
-  case POPUP_CUT_BUTTON_ICON :
+  case Toolkit::TextSelectionPopup::CUT :
   {
     return mCutIconImage;
   }
   break;
-  case POPUP_COPY_BUTTON_ICON :
+  case Toolkit::TextSelectionPopup::COPY :
   {
     return mCopyIconImage;
   }
   break;
-  case POPUP_PASTE_BUTTON_ICON :
+  case Toolkit::TextSelectionPopup::PASTE :
   {
     return mPasteIconImage;
   }
   break;
-  case POPUP_SELECT_BUTTON_ICON :
+  case Toolkit::TextSelectionPopup::SELECT :
   {
     return mSelectIconImage;
   }
   break;
-  case POPUP_SELECT_ALL_BUTTON_ICON :
+  case Toolkit::TextSelectionPopup::SELECT_ALL :
   {
     return mSelectAllIconImage;
   }
   break;
   default :
   {
-    DALI_ASSERT_DEBUG( "Unknown Popup Part" );
+    DALI_ASSERT_DEBUG( "TextSelectionPopup GetPopupImage Unknown Button" );
   }
   } // switch
 
@@ -374,64 +532,59 @@ Dali::Image TextSelectionPopup::GetPopupImage( PopupParts part )
    {
      mCutIconImage = ResourceImage::New( OPTION_ICON_CUT );
    }
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCut, mCutOptionPriority, OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), mCutIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CUT, mCutOptionPriority, OPTION_CUT, POPUP_CUT_STRING , mCutIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::CUT)  ) );
 
    if ( !mCopyIconImage )
    {
      mCopyIconImage = ResourceImage::New( OPTION_ICON_COPY );
    }
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsCopy, mCopyOptionPriority, OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), mCopyIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::COPY, mCopyOptionPriority, OPTION_COPY, POPUP_COPY_STRING, mCopyIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::COPY)  ) );
 
    if ( !mPasteIconImage )
    {
      mPasteIconImage = ResourceImage::New( OPTION_ICON_PASTE );
    }
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsPaste, mPasteOptionPriority, OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), mPasteIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::PASTE, mPasteOptionPriority, OPTION_PASTE, POPUP_PASTE_STRING, mPasteIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::PASTE)  ) );
 
    if ( !mSelectIconImage )
    mSelectIconImage = ResourceImage::New( OPTION_ICON_SELECT );
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelect, mSelectOptionPriority, OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), mSelectIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT, mSelectOptionPriority, OPTION_SELECT_WORD, POPUP_SELECT_STRING, mSelectIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT)  ) );
 
    if ( !mSelectAllIconImage )
    {
     mSelectAllIconImage = ResourceImage::New( OPTION_ICON_SELECT_ALL );
    }
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsSelectAll, mSelectAllOptionPriority, OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), mSelectAllIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT_ALL, mSelectAllOptionPriority, OPTION_SELECT_ALL, POPUP_SELECT_ALL_STRING, mSelectAllIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT_ALL)  ) );
 
    if ( !mClipboardIconImage )
    {
      mClipboardIconImage = ResourceImage::New( OPTION_ICON_CLIPBOARD );
    }
-   mOrderListOfButtons.push_back( ButtonRequirement( ButtonsClipboard, mClipboardOptionPriority, OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), mClipboardIconImage, true ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CLIPBOARD, mClipboardOptionPriority, OPTION_CLIPBOARD, POPUP_CLIPBOARD_STRING, mClipboardIconImage, ( mEnabledButtons & Toolkit::TextSelectionPopup::CLIPBOARD)  ) );
 
    // Sort the buttons according their priorities.
    std::sort( mOrderListOfButtons.begin(), mOrderListOfButtons.end(), TextSelectionPopup::ButtonPriorityCompare() );
  }
 
- void TextSelectionPopup::CreateBackground()
+ void TextSelectionPopup::AddOption( const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption  )
  {
-   if ( mBackgroundImage )
-   {
-     SetBackgroundImage (  mBackgroundImage );
-   }
 
-   SetBackgroundColor( mBackgroundColor );
- }
+   const std::string& name = button.name;
+   const std::string& caption = button.caption;
+   Image iconImage = button.icon;
 
- void TextSelectionPopup::AddOption( Dali::Toolkit::TableView& parent, const std::string& name, const std::string& caption, const Image iconImage, bool finalOption, bool showIcons, bool showCaption, std::size_t& indexInTable )
- {
    // 1. Create the backgrounds for the popup option both normal and pressed.
    // Both containers will be added to a button.
 
-   Toolkit::TableView optionContainer = Toolkit::TableView::New( (showIcons)?2:1 , 1 );
-   optionContainer.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
-   optionContainer.SetMinimumSize( Vector2( OPTION_MIN_WIDTH, 0 ) );
+   Toolkit::TableView optionContainer = Toolkit::TableView::New( (showIcons&showCaption)?2:1 , 1 );
+   optionContainer.SetFitHeight( 0 );
    optionContainer.SetFitWidth( 0 );
 
-   Toolkit::TableView  optionPressedContainer = Toolkit::TableView::New( (showIcons)?2:1 , 1 );
-   optionPressedContainer.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
-   optionPressedContainer.SetMinimumSize( Vector2( OPTION_MIN_WIDTH, 0 ) );
+   Toolkit::TableView  optionPressedContainer = Toolkit::TableView::New( (showIcons&showCaption)?2:1 , 1 );
+   optionPressedContainer.SetFitHeight( 0 );
    optionPressedContainer.SetFitWidth( 0 );
+   optionPressedContainer.SetBackgroundColor( mPressedColor );
+
 #ifdef DECORATOR_DEBUG
    optionContainer.SetName("optionContainer");
    optionPressedContainer.SetName("optionPressedContainer");
@@ -440,114 +593,122 @@ Dali::Image TextSelectionPopup::GetPopupImage( PopupParts part )
 
    if ( showCaption )
    {
-   Toolkit::TextLabel captionTextLabel = Toolkit::TextLabel::New();
-   captionTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, caption );
-   optionContainer.SetFitHeight( 0 );
-
-   Toolkit::TextLabel pressedCaptionTextLabel = Toolkit::TextLabel::New();
-   pressedCaptionTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, caption );
-   optionPressedContainer.SetFitHeight( 0 );
-
-   captionTextLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
-   captionTextLabel.SetMaximumSize( Vector2( OPTION_MAX_WIDTH - 2.f * OPTION_MARGIN_WIDTH , FLT_MAX ) ); //todo FLT_MAX Size negotiation feature needed
-
-   pressedCaptionTextLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
-   pressedCaptionTextLabel.SetMaximumSize( Vector2( OPTION_MAX_WIDTH - 2.f * OPTION_MARGIN_WIDTH , FLT_MAX) ); //todo FLT_MAX Size negotiation feature needed
-
-   optionContainer.AddChild( captionTextLabel, Toolkit::TableView::CellPosition( 1, 0 )  ); // todo Labels need ellipsis or similar
-   optionPressedContainer.AddChild( pressedCaptionTextLabel, Toolkit::TableView::CellPosition( 1, 0 )  ); // todo Labels need ellipsis or similar
+     Toolkit::TextLabel captionTextLabel = Toolkit::TextLabel::New();
+     captionTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, caption );
+     captionTextLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+     Toolkit::TextLabel pressedCaptionTextLabel = Toolkit::TextLabel::New();
+     pressedCaptionTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, caption );
+     pressedCaptionTextLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+     Padding padding;
+     padding.left = 24.0f;
+     padding.right = 24.0f;
+     padding.top = 14.0f;
+     padding.bottom = 14.0f;
+     captionTextLabel.SetPadding( padding );
+     pressedCaptionTextLabel.SetPadding( padding );
+
+     optionContainer.AddChild( captionTextLabel, Toolkit::TableView::CellPosition(( showIcons&showCaption)?1:0, 0 )  );
+     optionPressedContainer.AddChild( pressedCaptionTextLabel, Toolkit::TableView::CellPosition(( showIcons&showCaption)?1:0, 0 ) );
    }
 
+   // 3. Create the icons
    if ( showIcons )
    {
-     // 3. Create the icons
      ImageActor pressedIcon = ImageActor::New(  iconImage );
      ImageActor icon = ImageActor::New(  iconImage );
      icon.SetSortModifier( DECORATION_DEPTH_INDEX - 1 );
      pressedIcon.SetSortModifier( DECORATION_DEPTH_INDEX - 1 );
-     icon.SetName("image-icon-2014");
+
      icon.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
      pressedIcon.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
-     pressedIcon.SetColor( mIconPressedColor );
-     optionContainer.SetFitHeight( 0 );
-     optionPressedContainer.SetFitHeight( 0 );
+     icon.SetColor( mIconColor );
+
+     if ( showCaption & showIcons )
+     {
+       optionContainer.SetFitHeight( 1 );
+       optionContainer.SetFitWidth( 1 );
+       optionPressedContainer.SetFitHeight( 1 );
+       optionPressedContainer.SetFitWidth( 1 );
+     }
+
      optionContainer.AddChild( icon, Toolkit::TableView::CellPosition( 0, 0 )  );
      optionPressedContainer.AddChild( pressedIcon, Toolkit::TableView::CellPosition( 0, 0 )  );
+
      icon.SetPadding( Padding( 10.0f, 10.0f, 10.0f, 10.0f ) );
      pressedIcon.SetPadding( Padding( 10.0f, 10.0f, 10.0f, 10.0f ) );
    }
 
-   // 5. Create a option.
+   // 4. Create a option.
    Toolkit::PushButton option = Toolkit::PushButton::New();
    option.SetName( name );
    option.SetAnimationTime( 0.0f );
-   option.SetSize( OPTION_ICON_SIZE );
-   //option.ClickedSignal().Connect( this, &TextInputPopup::OnButtonPressed );
+   option.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
 
-   // 6. Set the normal option image.
+   switch( button.id )
+   {
+     case Toolkit::TextSelectionPopup::CUT:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCutButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::COPY:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCopyButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::PASTE:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnPasteButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::SELECT:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::SELECT_ALL:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectAllButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::CLIPBOARD:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnClipboardButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::NONE:
+     {
+       // Nothing to do:
+       break;
+     }
+   }
+
+   // 5. Set the normal option image.
    option.SetButtonImage( optionContainer );
 
-   // 7. Set the pressed option image
+   // 6. Set the pressed option image
    option.SetSelectedImage( optionPressedContainer );
 
-   // 9 Add option to table view
-   parent.SetFitWidth( indexInTable );
-   parent.AddChild( option, Toolkit::TableView::CellPosition( 0, indexInTable )  );
-   indexInTable++;
+   // 7 Add option to tool bar
+   mToolbar.AddOption( option );
 
-   // 10. Add the divider
-   if( !finalOption )
+   // 8. Add the divider
+   if( showDivider )
    {
-     const Size size( POPUP_DIVIDER_WIDTH, 0.0f ); // Height FILL_TO_PARENT
+     const Size size( mOptionDividerSize.width, 0.0f ); // Height FILL_TO_PARENT
 
      ImageActor divider = Toolkit::CreateSolidColorActor( Color::WHITE );
-
      divider.SetSize( size );
      divider.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
-     parent.SetFitWidth( indexInTable );
-     parent.AddChild( divider, Toolkit::TableView::CellPosition( 0, indexInTable )  );
-     indexInTable++;
+     divider.SetColor( mLineColor );
+     mToolbar.AddDivider( divider );
    }
  }
 
- void TextSelectionPopup::SetUpPopup()
- {
-   Actor self = Self();
-   self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
-
-   // Create Layer and Stencil.
-   mStencilLayer = Layer::New();
-   mStencilLayer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
-   mStencilLayer.SetParentOrigin( ParentOrigin::CENTER );
-
-   ImageActor stencil = CreateSolidColorActor( Color::RED );
-   stencil.SetDrawMode( DrawMode::STENCIL );
-   stencil.SetVisible( true );
-   stencil.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
-   stencil.SetParentOrigin( ParentOrigin::CENTER );
-
-   Actor scrollview = Actor::New(); //todo make a scrollview
-   scrollview.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
-   scrollview.SetParentOrigin( ParentOrigin::CENTER );
-
-   mTableOfButtons.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
-   mTableOfButtons.SetFitHeight( 0 );
-   mTableOfButtons.SetParentOrigin( ParentOrigin::CENTER );
-
-   mStencilLayer.Add( stencil );
-   mStencilLayer.Add( scrollview );
-   scrollview.Add( mTableOfButtons );
-   self.Add( mStencilLayer );
-   //self.Add ( mTableOfButtons );
- }
-
- void TextSelectionPopup::AddPopupOptions( bool createTail, bool showIcons, bool showCaptions )
+ std::size_t TextSelectionPopup::GetNumberOfEnabledOptions()
  {
-   mContentSize = Vector2::ZERO;
-
-   // Add the options into the buttons container.
-
-   // 1. Determine how many buttons are active and should be added to container.
    std::size_t numberOfOptions = 0u;
    for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
    {
@@ -558,56 +719,61 @@ Dali::Image TextSelectionPopup::GetPopupImage( PopupParts part )
      }
    }
 
-   // 2. Iterate list of buttons and add active ones.
-   std::size_t optionsAdded = 0u;
-
-   numberOfOptions = ( numberOfOptions*2 ) - 1 ; // Last Option does not get a divider so -1 or if only one option then also no divider
-
-   mTableOfButtons = Dali::Toolkit::TableView::New( 1, numberOfOptions );
+   return numberOfOptions;
+ }
 
+ void TextSelectionPopup::AddPopupOptionsToToolbar( bool showIcons, bool showCaptions )
+ {
+   // Iterate list of buttons and add active ones to Toolbar
+   std::size_t numberOfOptionsRequired =  GetNumberOfEnabledOptions();
+   std::size_t numberOfOptionsAdded = 0u;
    for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
    {
      const ButtonRequirement& button( *it );
      if ( button.enabled )
      {
-       AddOption( mTableOfButtons, button.name, button.caption, button.icon, optionsAdded == numberOfOptions - 1, showIcons, showCaptions, optionsAdded ); // -1 to ignore the last divider
+       numberOfOptionsAdded++;
+       AddOption(  button, ( numberOfOptionsAdded < numberOfOptionsRequired ) , showIcons, showCaptions );
      }
    }
  }
 
  void TextSelectionPopup::CreatePopup()
  {
-   if ( !mStencilLayer )
+   Actor self = Self();
+   CreateOrderedListOfPopupOptions();  //todo Currently causes all options to be shown
+   self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+   SetBackgroundImage( NinePatchImage::New( DEFAULT_POPUP_BACKGROUND_IMAGE ) );
+
+   if ( !mToolbar )
    {
-     CreateOrderedListOfPopupOptions();  //todo Currently causes all options to be shown
-     CreateBackground();
-     AddPopupOptions( true, true, false );  // todo false so not to show Labels until ellipses or similar possible.
-     SetUpPopup();
+     mToolbar = Toolkit::TextSelectionToolbar::New();
+     mToolbar.SetParentOrigin( ParentOrigin::CENTER );
+     mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, mMaxSize );
+     self.Add( mToolbar );
+     AddPopupOptionsToToolbar( mShowIcons, mShowCaptions );
    }
-
-   mStencilLayer.RaiseToTop();
  }
 
-TextSelectionPopup::TextSelectionPopup()
-: Control( ControlBehaviour( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ) ),
-  mMaxSize ( DEFAULT_POPUP_MAX_SIZE ),
-  mVisiblePopUpSize( DEFAULT_POPUP_MAX_SIZE ),
-  mRequiredPopUpSize( DEFAULT_POPUP_MAX_SIZE ),
-  mBackgroundColor( DEFAULT_POPUP_BACKGROUND ),
-  mBackgroundPressedColor( DEFAULT_POPUP_BACKGROUND_PRESSED ),
+TextSelectionPopup::TextSelectionPopup( TextSelectionPopupCallbackInterface* callbackInterface )
+: Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
+  mToolbar(),
+  mMaxSize(),
+  mMinSize(),
+  mOptionDividerSize( Size( 2.0f, 0.0f) ),
+  mEnabledButtons( Toolkit::TextSelectionPopup::NONE ),
+  mCallbackInterface( callbackInterface ),
   mLineColor( DEFAULT_POPUP_LINE_COLOR ),
   mIconColor( DEFAULT_OPTION_ICON ),
-  mIconPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
-  mTextColor( DEFAULT_OPTION_TEXT ),
-  mTextPressedColor( DEFAULT_OPTION_TEXT_PRESSED ),
+  mPressedColor( DEFAULT_OPTION_ICON_PRESSED ),
   mSelectOptionPriority( 1 ),
   mSelectAllOptionPriority ( 2 ),
   mCutOptionPriority ( 3 ),
   mCopyOptionPriority ( 4 ),
   mPasteOptionPriority ( 5 ),
   mClipboardOptionPriority( 6 ),
-  mShowIcons( true ),
-  mShowCaptions( false )
+  mShowIcons( false ),
+  mShowCaptions( true )
 {
 }
 
@@ -621,3 +787,5 @@ TextSelectionPopup::~TextSelectionPopup()
 } // namespace Toolkit
 
 } // namespace Dali
+
+
index 892c563..c409983 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/buttons/push-button.h>
 #include <dali-toolkit/public-api/controls/table-view/table-view.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/actors/image-actor.h>
@@ -38,15 +40,14 @@ namespace Internal
 
 namespace
 {
-enum PopupParts
+
+enum PopupCustomisations
 {
-  POPUP_BACKGROUND,
-  POPUP_CLIPBOARD_BUTTON,
-  POPUP_CUT_BUTTON_ICON,
-  POPUP_COPY_BUTTON_ICON,
-  POPUP_PASTE_BUTTON_ICON,
-  POPUP_SELECT_BUTTON_ICON,
-  POPUP_SELECT_ALL_BUTTON_ICON,
+  POPUP_MAXIMUM_SIZE,
+  POPUP_MINIMUM_SIZE,
+  OPTION_MAXIMUM_SIZE,
+  OPTION_MINIMUM_SIZE,
+  OPTION_DIVIDER_SIZE
 };
 
 } // namespace
@@ -55,21 +56,10 @@ class TextSelectionPopup : public Control
 {
 public:
 
-  enum Buttons
-  {
-    ButtonsCut,
-    ButtonsCopy,
-    ButtonsPaste,
-    ButtonsSelect,
-    ButtonsSelectAll,
-    ButtonsClipboard,
-    ButtonsEnumEnd
-  };
-
   struct ButtonRequirement
   {
     ButtonRequirement()
-    : id( ButtonsEnumEnd ),
+    : id( Toolkit::TextSelectionPopup::NONE ),
       priority( 0u ),
       name(),
       caption(),
@@ -77,7 +67,7 @@ public:
       enabled( false )
     {}
 
-    ButtonRequirement( Buttons buttonId,
+    ButtonRequirement( Toolkit::TextSelectionPopup::Buttons buttonId,
                        std::size_t buttonPriority,
                        const std::string& buttonName,
                        const std::string& buttonCaption,
@@ -91,7 +81,7 @@ public:
       enabled( buttonEnabled )
     {}
 
-    Buttons id;
+    Toolkit::TextSelectionPopup::Buttons id;
     std::size_t priority;
     std::string name;
     std::string caption;
@@ -106,15 +96,14 @@ public:
       }
   };
 
-//  static inline bool ButtonPriorityCompare( ButtonRequirement a, ButtonRequirement b )
-//  {
-//    return a.priority < b.priority ? true : false;
-//  }
-
   /**
-   * @copydoc Dali::Toollkit::TextSelectionPopup::New()
+   * @brief New constructor with provided buttons to enable.
+   * @param[in] buttonsToEnable bit mask of buttons to enable
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   * @return A handle to the TextSelectionPopup control.
    */
-  static Toolkit::TextSelectionPopup New();
+  static Toolkit::TextSelectionPopup New( Toolkit::TextSelectionPopup::Buttons buttonsToEnable,
+                                          TextSelectionPopupCallbackInterface* callbackInterface );
 
   // Properties
 
@@ -135,86 +124,102 @@ public:
    */
   static Property::Value GetProperty( BaseObject* object, Property::Index index );
 
-  void CreatePopup();
-
-  void DestroyPopup();
-
 private: // From Control
 
   /**
    * @copydoc Control::OnInitialize()
    */
- virtual void OnInitialize();
-
-//  /**
-//   * @copydoc Control::GetNaturalSize()
-//   */
-//  virtual Vector3 GetNaturalSize();
-//
-//  /**
-//   * @copydoc Control::GetHeightForWidth()
-//   */
-//  virtual float GetHeightForWidth( float width );
+  virtual void OnInitialize();
+
+private: // Implementation
 
   /**
-   * @copydoc Control::OnInitialize()
+   * @brief When the cut button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
    */
-  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
-//
-//  /**
-//   * Received for single & double taps
-//   */
-//  virtual void OnTap( const TapGesture& tap );
-//
-//  /**
-//   * @copydoc Text::ControlInterface::RequestTextRelayout()
-//   */
-//  virtual void RequestTextRelayout();
+  bool OnCutButtonPressed( Toolkit::Button button );
 
   /**
-   * Set max size of Popup
-   * @param[in] maxSize Size (Vector2)
+   * @brief When the copy button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
    */
-  void SetPopupMaxSize( const Size& maxSize );
+  bool OnCopyButtonPressed( Toolkit::Button button );
 
   /**
-   * Get Max size of Popup
-   * @return Vector2 the max size of the Popup
+   * @brief When the paste button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
    */
-  const Dali::Vector2& GetPopupMaxSize() const;
+  bool OnPasteButtonPressed( Toolkit::Button button );
 
   /**
-   * @brief Sets the image for the given part of the Popup.
+   * @brief When the select button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnSelectButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the select all button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnSelectAllButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the clipboard button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnClipboardButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief Method to set the dimension or dimension constraint on certain aspects of the Popup.
+   *
+   * @param[in] settingToCustomise The setting for the PopupCustomisations enum that can be customised
+   * @param[in] dimension The size to customise with
+   */
+  void SetDimensionToCustomise( const PopupCustomisations& settingToCustomise, const Size& dimension );
+
+  /**
+   * @brief Method to get the dimension or dimension constraint on certain aspects of the Popup that was previously customised
+   *
+   * @param[in] setting The setting from the PopupCustomisations enum
+   */
+  Size GetDimensionToCustomise( const PopupCustomisations& setting );
+
+  /**
+   * @brief Sets the image for the given button of the Popup.
    *
-   * @param[in] part  The part of the pop from the Enum PopupParts
+   * @param[in] button  The button the image should be used for from the Buttons Enum.
    * @param[in] image The image to use.
    */
- void SetPopupImage( PopupParts part, Dali::Image image );
+ void SetButtonImage( Toolkit::TextSelectionPopup::Buttons button, Dali::Image image );
 
   /**
-   * @brief Retrieves the image of the given part used by the popup
+   * @brief Retrieves the image of the given button used by the popup
    *
-   * @param[in] part The part of the popup
-   * @return The image used for that part.
+   * @param[in] button The button to get the image from
+   * @return The image used for that button.
    */
-  Dali::Image GetPopupImage( PopupParts part );
+  Dali::Image GetButtonImage( Toolkit::TextSelectionPopup::Buttons button );
 
   void CreateOrderedListOfPopupOptions();
 
-  void CreateBackground();
+  void AddOption( const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption );
 
-  void AddOption( Dali::Toolkit::TableView& parent, const std::string& name, const std::string& caption, const Image iconImage, bool finalOption, bool showIcons, bool showCaption, std::size_t& indexInTable  );
+  std::size_t GetNumberOfEnabledOptions();
 
-  void SetUpPopup();
+  void AddPopupOptionsToToolbar(  bool showIcons, bool showCaptions );
 
-  void AddPopupOptions( bool createTail, bool showIcons, bool showCaptions );
-
-private: // Implementation
+  void CreatePopup();
 
   /**
    * Construct a new TextField.
    */
-  TextSelectionPopup();
+  TextSelectionPopup( TextSelectionPopupCallbackInterface* callbackInterface );
 
   /**
    * A reference counted object may only be deleted by calling Unreference()
@@ -229,11 +234,12 @@ private:
 
 private: // Data
 
-  Dali::Toolkit::TableView mTableOfButtons;                          // Actor which holds all the buttons, sensitivity can be set on buttons via this actor
-  Layer mStencilLayer;                                // Layer to enable clipping when buttons exceed popup
 
-  // Images to be used by the Popup
-  Image mBackgroundImage;
+  Dali::Toolkit::TextSelectionToolbar mToolbar;
+
+  Dali::Toolkit::TableView mTableOfButtons;           // Actor which holds all the buttons, sensitivity can be set on buttons via this actor
+
+  // Images to be used by the Popup buttons
   Image mCutIconImage;
   Image mCopyIconImage;
   Image mPasteIconImage;
@@ -241,29 +247,21 @@ private: // Data
   Image mSelectIconImage;
   Image mSelectAllIconImage;
 
-  ImageActor mBackground;                             // The background popup panel
-  ImageActor mTail;                                   // The tail for the popup
-  ImageActor mTailEffect;   //todo remove                          // the tail effect
-  ImageActor mTailLine;     //todo remove                          // The border/outline around the tail
+  Size mMaxSize;                       // Maximum size of the Popup
+  Size mMinSize;                       // Minimum size of the Popup
 
-  Size mMaxSize;                                      // Max size of the Popup
-  Size mVisiblePopUpSize;                             // Visible Size of popup excluding content that needs scrolling.
-  Size mRequiredPopUpSize;                            // Total size of popup including any invisible margin
-
-  Vector4 mNinePatchMargins;                          // Margins between the edge of the cropped image and the nine patch rect (left, right, top, bottom).
-
-  Size mContentSize;                                  // Size of Content (i.e. Buttons)
-  //Animation mAnimation;                               // Popup Hide/Show animation.
+  Size mOptionMaxSize;                 // Maximum size of an Option button
+  Size mOptionMinSize;                 // Minimum size of an Option button
+  Size mOptionDividerSize;             // Size of divider line
 
   std::vector<ButtonRequirement> mOrderListOfButtons; // List of buttons in the order to be displayed and a flag to indicate if needed.
 
-  Vector4 mBackgroundColor;             // Color of the background of the text input popup
-  Vector4 mBackgroundPressedColor;      // Color of the option background.
+  Toolkit::TextSelectionPopup::Buttons mEnabledButtons; // stores enabled buttons
+  Toolkit::TextSelectionPopupCallbackInterface* mCallbackInterface;
+
   Vector4 mLineColor;                   // Color of the line around the text input popup
   Vector4 mIconColor;                   // Color of the popup icon.
-  Vector4 mIconPressedColor;            // Color of the popup icon when pressed.
-  Vector4 mTextColor;                   // Color of the popup text.
-  Vector4 mTextPressedColor;            // Color of the popup text when pressed.
+  Vector4 mPressedColor;                // Color of the popup option when pressed.
 
   // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right.
   std::size_t mSelectOptionPriority;    // Position of Select Button
@@ -273,8 +271,8 @@ private: // Data
   std::size_t mPasteOptionPriority;     // Position of Paste button
   std::size_t mClipboardOptionPriority; // Position of Clipboard button
 
-  bool mShowIcons; // Flag to show icons
-  bool mShowCaptions; // Flag to show text captions
+  bool mShowIcons:1; // Flag to show icons
+  bool mShowCaptions:1; // Flag to show text captions
 
 };
 
@@ -305,3 +303,4 @@ inline const Toolkit::Internal::TextSelectionPopup& GetImpl( const Toolkit::Text
 } // namespace Dali
 
 #endif // __DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_H__
+
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp
new file mode 100644 (file)
index 0000000..cb1e205
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2015 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/text-controls/text-selection-toolbar-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/devel-api/object/type-registry-helper.h>
+#include <cfloat>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const Dali::Vector2 DEFAULT_MAX_SIZE( 400.0f, 65.0f ); ///< The maximum size of the Toolbar.
+
+BaseHandle Create()
+{
+  return Toolkit::TextSelectionToolbar::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionToolbar, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "max-size", VECTOR2, MAX_SIZE )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Dali::Toolkit::TextSelectionToolbar TextSelectionToolbar::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextSelectionToolbar > impl = new TextSelectionToolbar();
+
+  // Pass ownership to CustomActor handle
+  Dali::Toolkit::TextSelectionToolbar handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextSelectionToolbar::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
+      {
+       impl.SetPopupMaxSize( value.Get< Vector2 >() );
+       break;
+      }
+
+    } // switch
+  } // TextSelectionToolbar
+}
+
+Property::Value TextSelectionToolbar::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
+      {
+        value = impl.GetPopupMaxSize();
+        break;
+      }
+    } // switch
+  }
+  return value;
+}
+
+void TextSelectionToolbar::OnInitialize()
+{
+  SetUp();
+}
+
+void TextSelectionToolbar::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  float width = std::max ( mTableOfButtons.GetNaturalSize().width, size.width );
+  mRulerX->SetDomain( RulerDomain( 0.0, width, true ) );
+  mScrollView.SetRulerX( mRulerX );
+}
+
+void TextSelectionToolbar::SetPopupMaxSize( const Size& maxSize )
+{
+  mMaxSize = maxSize;
+}
+
+const Dali::Vector2& TextSelectionToolbar::GetPopupMaxSize() const
+{
+  return mMaxSize;
+}
+
+void TextSelectionToolbar::SetUpScrollView( Toolkit::ScrollView& scrollView )
+{
+  scrollView.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+  scrollView.SetMaximumSize( mMaxSize );
+
+  scrollView.SetScrollingDirection( PanGestureDetector::DIRECTION_HORIZONTAL, Degree( 40.0f ) );
+  scrollView.SetAxisAutoLock( true );
+  scrollView.ScrollStartedSignal().Connect( this, &TextSelectionToolbar::OnScrollStarted );
+  scrollView.ScrollCompletedSignal().Connect( this, &TextSelectionToolbar::OnScrollCompleted );
+
+  mRulerX = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+
+  RulerPtr rulerY = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+  rulerY->Disable();
+  scrollView.SetRulerY( rulerY );
+}
+
+void TextSelectionToolbar::SetUp()
+{
+  Actor self = Self();
+  self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+
+  // Create Layer and Stencil.  Layer enable's clipping when content exceed maximum defined width.
+  Layer stencilLayer = Layer::New();
+  stencilLayer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  stencilLayer.SetParentOrigin( ParentOrigin::CENTER );
+  stencilLayer.SetMaximumSize( mMaxSize );
+
+  ImageActor stencil = CreateSolidColorActor( Color::RED );
+  stencil.SetDrawMode( DrawMode::STENCIL );
+  stencil.SetVisible( true );
+  stencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  stencil.SetParentOrigin( ParentOrigin::CENTER );
+
+  mScrollView  = Toolkit::ScrollView::New();
+  SetUpScrollView( mScrollView );
+
+  // Toolbar must start with at least one option, adding further options with increase it's size
+  mTableOfButtons = Dali::Toolkit::TableView::New( 1, 1 );
+  mTableOfButtons.SetFitHeight( 0 );
+  mTableOfButtons.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  mTableOfButtons.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+
+
+  stencilLayer.Add( stencil );
+  stencilLayer.Add( mScrollView );
+  mScrollView.Add( mTableOfButtons );
+  self.Add( stencilLayer );
+
+  stencilLayer.RaiseToTop();
+}
+
+void TextSelectionToolbar::OnScrollStarted( const Vector2& position )
+{
+  mTableOfButtons.SetSensitive( false );
+}
+
+void TextSelectionToolbar::OnScrollCompleted( const Vector2& position )
+{
+  mTableOfButtons.SetSensitive( true );
+}
+
+void TextSelectionToolbar::AddOption( Actor& option )
+{
+  mTableOfButtons.AddChild( option, Toolkit::TableView::CellPosition( 0, mIndexInTable )  );
+  mTableOfButtons.SetFitWidth( mIndexInTable );
+  mIndexInTable++;
+}
+
+void TextSelectionToolbar::AddDivider( Actor& divider )
+{
+  AddOption( divider );
+  mDividerIndexes.PushBack( mIndexInTable );
+}
+
+void TextSelectionToolbar::ResizeDividers( Size& size )
+{
+  for( unsigned int i = 0; i < mDividerIndexes.Count(); ++i )
+  {
+    Actor divider = mTableOfButtons.GetChildAt( Toolkit::TableView::CellPosition( 0, mDividerIndexes[ i ] ) );
+    divider.SetSize( size );
+  }
+  RelayoutRequest();
+}
+
+TextSelectionToolbar::TextSelectionToolbar()
+: Control( ControlBehaviour( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ) ),
+  mMaxSize ( DEFAULT_MAX_SIZE ),
+  mIndexInTable( 0 ),
+  mDividerIndexes()
+{
+}
+
+TextSelectionToolbar::~TextSelectionToolbar()
+{
+  mRulerX.Reset();
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h
new file mode 100644 (file)
index 0000000..3593e79
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H__
+#define __DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H__
+
+/*
+ * Copyright (c) 2015 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/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+} // namespace
+
+class TextSelectionToolbar : public Control
+{
+public:
+
+  /**
+   * @copydoc Dali::Toollkit::TextSelectionToolbar::New()
+   */
+  static Toolkit::TextSelectionToolbar New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   *  @copydoc TextSelectionToolbar::AddOption
+   */
+  void AddOption( Actor& option );
+
+  /**
+   *  @copydoc TextSelectionToolbar::AddDivider
+   */
+  void AddDivider( Actor& divider );
+
+  /**
+   * @copydoc ResizeDividers
+   */
+  void ResizeDividers( Size& size );
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+  * @copydoc Control::OnRelayout()
+  */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+  /**
+   * @brief Set max size of Popup
+   * @param[in] maxSize Size (Vector2)
+   */
+  void SetPopupMaxSize( const Size& maxSize );
+
+  /**
+   * @brief Get Max size of Popup
+   * @return Vector2 the max size of the Popup
+   */
+  const Dali::Vector2& GetPopupMaxSize() const;
+
+  /**
+   * @brief Set up scrollview to scroll Toolbar horizontally
+   * @param[out] scrollView scrollview to setup
+   */
+  void SetUpScrollView( Toolkit::ScrollView& scrollView );
+
+  /**
+   * @brief Set up the parts that make the Toolbar
+   */
+  void SetUp();
+
+  /**
+   * Toolbar has started to scroll
+   * @param[in] position current scroll view position
+   */
+  void OnScrollStarted( const Vector2& position );
+
+  /**
+   * Toolbar has stopped scrolling
+   * @param[in] position current scroll view position
+   */
+  void OnScrollCompleted( const Vector2& position );
+
+private: // Implementation
+
+  /**
+   * Construct a new TextField.
+   */
+  TextSelectionToolbar();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextSelectionToolbar();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  TextSelectionToolbar(const TextSelectionToolbar&);
+  TextSelectionToolbar& operator=(const TextSelectionToolbar& rhs);
+
+private: // Data
+
+  Toolkit::TableView mTableOfButtons;                 // Actor which holds all the buttons, sensitivity can be set on buttons via this actor
+  Toolkit::ScrollView mScrollView;                    // Provides scrolling of Toolbar when content does not fit.
+  RulerPtr mRulerX;                                   // Ruler to clamp horizontal scrolling. Updates on Relayout
+  Size mMaxSize;                                      // Max size of the Toolbar
+  unsigned int mIndexInTable;                         // Index in table to add option
+  Dali::Vector< unsigned int > mDividerIndexes;       // Vector of indexes in the Toolbar that contain dividers.
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextSelectionToolbar& GetImpl( Toolkit::TextSelectionToolbar& textSelectionToolbar )
+{
+  DALI_ASSERT_ALWAYS( textSelectionToolbar );
+
+  Dali::RefObject& handle = textSelectionToolbar.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextSelectionToolbar&>(handle);
+}
+
+inline const Toolkit::Internal::TextSelectionToolbar& GetImpl( const Toolkit::TextSelectionToolbar& textSelectionToolbar )
+{
+  DALI_ASSERT_ALWAYS( textSelectionToolbar );
+
+  const Dali::RefObject& handle = textSelectionToolbar.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextSelectionToolbar&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H__
index e48339e..64a51e3 100644 (file)
@@ -48,6 +48,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/text-controls/text-field-impl.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 \
    $(toolkit_src_dir)/controls/tool-bar/tool-bar-impl.cpp \
    $(toolkit_src_dir)/focus-manager/accessibility-focus-manager-impl.cpp \
    $(toolkit_src_dir)/focus-manager/keyboard-focus-manager-impl.cpp \
index 728bd42..447a73b 100644 (file)
@@ -23,7 +23,7 @@
 #include <dali/public-api/actors/layer.h>
 #include <dali/devel-api/adaptor-framework/accessibility-manager.h>
 #include <dali/devel-api/adaptor-framework/sound-player.h>
-#include <dali/devel-api/adaptor-framework/tts-player.h>
+#include <dali/public-api/adaptor-framework/tts-player.h>
 #include <dali/public-api/animation/constraints.h>
 #include <dali/devel-api/events/hit-test-algorithm.h>
 #include <dali/public-api/images/resource-image.h>
@@ -190,7 +190,7 @@ void AccessibilityFocusManager::SetFocusOrder(Actor actor, const unsigned int or
     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
     if(propertyActorFocusable == Property::INVALID_INDEX)
     {
-      propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
+      propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE );
     }
 
     if(order == 0)
@@ -511,7 +511,7 @@ void AccessibilityFocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
     if(propertyIsFocusGroup == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
+      actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
     }
     else
     {
@@ -654,7 +654,7 @@ void AccessibilityFocusManager::SetFocusable(Actor actor, bool focusable)
     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
     if(propertyActorFocusable == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
+      actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
     }
     else
     {
index 19573e8..5be38ac 100644 (file)
@@ -397,7 +397,7 @@ void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
     if(propertyIsFocusGroup == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup);
+      actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE );
     }
     else
     {
index 135f71b..cf9ec63 100644 (file)
@@ -162,13 +162,6 @@ void SetBidirectionalInfo( const Vector<Character>& text,
   }
 }
 
-void ReplaceBidirectionalInfo( LogicalModel& model,
-                               CharacterIndex characterIndex,
-                               Length numberOfCharactersToRemove,
-                               Length numberOfCharactersToInsert )
-{
-}
-
 void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
                    Vector<LineRun>& lineRuns,
                    Vector<BidirectionalLineInfoRun>& lineInfoRuns )
@@ -234,14 +227,6 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
   }
 }
 
-void ReorderLines( LogicalModel& logicalModel,
-                   const VisualModel& visualModel,
-                   CharacterIndex characterIndex,
-                   Length numberOfCharactersToRemove,
-                   Length numberOfCharactersToInsert )
-{
-}
-
 bool GetMirroredText( const Vector<Character>& text,
                       Vector<Character>& mirroredText )
 {
index f51e5e7..2f3b251 100644 (file)
@@ -53,25 +53,6 @@ void SetBidirectionalInfo( const Vector<Character>& text,
                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo );
 
 /**
- * Replaces the bidirectional info from the logical model.
- *
- * @pre The @p model needs to have a text set.
- * @pre The @p model needs to have the line break info set.
- *
- * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
- * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
- *
- * @param[in,out] model The text's logical model.
- * @param[in] characterIndex Index to the first character.
- * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
- * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
- */
-void ReplaceBidirectionalInfo( LogicalModel& model,
-                               CharacterIndex characterIndex,
-                               Length numberOfCharactersToRemove,
-                               Length numberOfCharactersToInsert );
-
-/**
  * Sets the visual to logical map tables.
  *
  * Any map tables previously set are removed.
@@ -90,28 +71,6 @@ void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInf
                    Vector<BidirectionalLineInfoRun>& lineInfoRuns );
 
 /**
- * Replaces the visual to logical and logical to visual map tables.
- *
- * @pre The @p logicalModel needs to have a text set.
- * @pre The @p logicalModel needs to have the line break info set.
- * @pre The @p visualModel needs to have the laid-out lines info set.
- *
- * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
- * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
- *
- * @param[in,out] logicalModel The text's logical model.
- * @param[in] visualModel The text's visual model.
- * @param[in] characterIndex Index to the first character.
- * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
- * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
- */
-void ReorderLines( LogicalModel& logicalModel,
-                   const VisualModel& visualModel,
-                   CharacterIndex characterIndex,
-                   Length numberOfCharactersToRemove,
-                   Length numberOfCharactersToInsert );
-
-/**
  * @brief Replaces any character which could be mirrored.
  *
  * @param[in] text The text.
index b1b9993..67c294b 100644 (file)
@@ -24,6 +24,9 @@ namespace Dali
 namespace Toolkit
 {
 
+namespace Text
+{
+
 namespace
 {
   const static uint8_t U1 = 1u;
@@ -222,6 +225,8 @@ void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std:
   Utf32ToUtf8( utf32, numberOfCharacters, reinterpret_cast<uint8_t*>(&utf8[0]) );
 }
 
+} // namespace Text
+
 } // namespace Toolkit
 
 } // namespace Dali
index 19784fb..720114b 100644 (file)
@@ -31,6 +31,9 @@ namespace Dali
 namespace Toolkit
 {
 
+namespace Text
+{
+
 /**
  * @brief Retrieves the number of characters of the text array encoded in UTF8
  *
@@ -86,6 +89,8 @@ uint32_t Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters,
  */
 void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std::string& utf8 );
 
+} // namespace Text
+
 } // namespace Toolkit
 
 } // namespace Dali
index 8b0f77f..e9c6e8f 100644 (file)
@@ -79,6 +79,8 @@ void Clipper::Refresh( const Vector2& size )
                                                                offscreenSize.height,
                                                                Pixel::RGBA8888 );
 
+    mOffscreenRootActor.SetSize( size );
+
     mImageActor.SetSize( offscreenSize );
     mImageActor.SetImage( frameBufferImage );
     mRenderTask.SetTargetFrameBuffer( frameBufferImage );
index 8e7529a..e12ddca 100644 (file)
@@ -73,13 +73,17 @@ namespace
 
 const char* DEFAULT_GRAB_HANDLE_IMAGE_RELEASED( DALI_IMAGE_DIR "insertpoint-icon.png" );
 const char* DEFAULT_GRAB_HANDLE_IMAGE_PRESSED( DALI_IMAGE_DIR "insertpoint-icon-pressed.png" );
-const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
-const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
+const char* DEFAULT_SELECTION_HANDLE_ONE_RELEASED( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
+const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" );
+const char* DEFAULT_SELECTION_HANDLE_TWO_RELEASED( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
+const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
 
-const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
-const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
+const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
 
-const Dali::Vector4 LIGHT_BLUE( 0.07f, 0.41f, 0.59f, 1.0f ); // The text highlight color.
+const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+
+const Dali::Vector4 LIGHT_BLUE( (0xb2 / 255.0f), (0xeb / 255.0f), (0xf2 / 255.0f), 0.5f ); // The text highlight color.
 
 const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
 const float TO_MILLISECONDS = 1000.f;
@@ -191,6 +195,7 @@ struct Decorator::Impl : public ConnectionTracker
       grabDisplacementY( 0.f ),
       active( false ),
       visible( false ),
+      pressed( false ),
       flipped( false )
     {
     }
@@ -204,14 +209,31 @@ struct Decorator::Impl : public ConnectionTracker
     float grabDisplacementY;
     bool active  : 1;
     bool visible : 1;
+    bool pressed : 1;
     bool flipped : 1;
   };
 
-  Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
-  : mTextControlParent( parent ),
-    mObserver( observer ),
+  struct PopupImpl
+  {
+    PopupImpl()
+    : position(),
+      offset( DEFAULT_POPUP_OFFSET )
+    {
+    }
+
+    TextSelectionPopup actor;
+    Vector3 position;
+    int offset;
+  };
+
+  Impl( ControllerInterface& controller,
+        TextSelectionPopupCallbackInterface& callbackInterface )
+  : mController( controller ),
+    mEnabledPopupButtons( TextSelectionPopup::NONE ),
+    mTextSelectionPopupCallbackInterface( callbackInterface ),
     mBoundingBox( Rect<int>() ),
     mHighlightColor( LIGHT_BLUE ),
+    mHighlightPosition( Vector2::ZERO ),
     mActiveCursor( ACTIVE_CURSOR_NONE ),
     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
     mCursorBlinkDuration( 0.0f ),
@@ -223,7 +245,9 @@ struct Decorator::Impl : public ConnectionTracker
     mActiveCopyPastePopup( false ),
     mCursorBlinkStatus( true ),
     mPrimaryCursorVisible( false ),
-    mSecondaryCursorVisible( false )
+    mSecondaryCursorVisible( false ),
+    mSwapSelectionHandles( false ),
+    mNotifyEndOfScroll( false )
   {
   }
 
@@ -246,17 +270,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 );
@@ -283,18 +296,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 )
@@ -318,15 +319,32 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
     if( primary.active || secondary.active )
     {
-      SetupTouchEvents();
+      Vector2 primaryPosition = primary.position;
+      Vector2 secondaryPosition = secondary.position;
+
+      const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
+      const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
+
+      if( isPrimaryVisible || isSecondaryVisible )
+      {
+        SetupTouchEvents();
 
-      CreateSelectionHandles();
+        CreateSelectionHandles();
 
-      primary.actor.SetPosition( primary.position.x,
-                                 primary.position.y + primary.lineHeight );
+        if( isPrimaryVisible )
+        {
+          primary.actor.SetPosition( primaryPosition.x,
+                                     primaryPosition.y + primary.lineHeight );
+        }
 
-      secondary.actor.SetPosition( secondary.position.x,
-                                   secondary.position.y + secondary.lineHeight );
+        if( isSecondaryVisible )
+        {
+          secondary.actor.SetPosition( secondaryPosition.x,
+                                       secondaryPosition.y + secondary.lineHeight );
+        }
+      }
+      primary.actor.SetVisible( isPrimaryVisible );
+      secondary.actor.SetVisible( isSecondaryVisible );
 
       CreateHighlight();
       UpdateHighlight();
@@ -340,22 +358,24 @@ struct Decorator::Impl : public ConnectionTracker
 
     if ( mActiveCopyPastePopup )
     {
-      if ( !mCopyPastePopup )
+      // todo Swap UnparentAndReset for DeterminePositionPopup() if mCopyPastePopup.actor valid Once the issue with the labels disappearing is fixed.
+      UnparentAndReset( mCopyPastePopup.actor );
+      if ( !mCopyPastePopup.actor )
       {
-        mCopyPastePopup = TextSelectionPopup::New();
+        mCopyPastePopup.actor = TextSelectionPopup::New( mEnabledPopupButtons, &mTextSelectionPopupCallbackInterface );
 #ifdef DECORATOR_DEBUG
-        mCopyPastePopup.SetName("mCopyPastePopup");
+        mCopyPastePopup.actor.SetName("mCopyPastePopup");
 #endif
-        mCopyPastePopup.SetAnchorPoint( AnchorPoint::CENTER );
-        mCopyPastePopup.OnRelayoutSignal().Connect( this,  &Decorator::Impl::PopUpRelayoutComplete  ); // Position popup after size negotiation
-        mActiveLayer.Add ( mCopyPastePopup );
+        mCopyPastePopup.actor.SetAnchorPoint( AnchorPoint::CENTER );
+        mCopyPastePopup.actor.OnRelayoutSignal().Connect( this,  &Decorator::Impl::PopupRelayoutComplete  ); // Position popup after size negotiation
+        mActiveLayer.Add ( mCopyPastePopup.actor );
       }
     }
     else
     {
-     if ( mCopyPastePopup )
+     if ( mCopyPastePopup.actor )
      {
-       UnparentAndReset( mCopyPastePopup );
+       UnparentAndReset( mCopyPastePopup.actor );
      }
     }
   }
@@ -367,25 +387,46 @@ struct Decorator::Impl : public ConnectionTracker
     mHandle[ GRAB_HANDLE ].position += scrollOffset;
     mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset;
     mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset;
-
-    // TODO Highlight box??
+    mHighlightPosition += scrollOffset;
   }
 
-  void PopUpRelayoutComplete( Actor actor )
+  void DeterminePositionPopup()
   {
-    // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+    if ( !mActiveCopyPastePopup )
+    {
+      return;
+    }
 
-    mCopyPastePopup.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopUpRelayoutComplete  );
+    if ( mHandle[LEFT_SELECTION_HANDLE].active || mHandle[RIGHT_SELECTION_HANDLE].active )
+    {
+      float minHandleXPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
+      float maxHandleXPosition = std::max (  mHandle[LEFT_SELECTION_HANDLE].position.x, mHandle[RIGHT_SELECTION_HANDLE].position.x );
 
-    Vector3 popupPosition( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f); //todo 100 to be an offset Property
+      float minHandleYPosition = std::min (  mHandle[LEFT_SELECTION_HANDLE].position.y, mHandle[RIGHT_SELECTION_HANDLE].position.y );
 
-    Vector3 popupSize = Vector3( mCopyPastePopup.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+      mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) *0.5f );
+      mCopyPastePopup.position.y = minHandleYPosition + mCopyPastePopup.offset;
+    }
+    else
+    {
+      mCopyPastePopup.position = Vector3( mCursor[PRIMARY_CURSOR].position.x, mCursor[PRIMARY_CURSOR].position.y -100.0f , 0.0f ); //todo 100 to be an offset Property
+    }
+
+    Vector3 popupSize = Vector3( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
 
-    GetConstrainedPopupPosition( popupPosition, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
+    GetConstrainedPopupPosition( mCopyPastePopup.position, popupSize, AnchorPoint::CENTER, mActiveLayer, mBoundingBox );
 
-    SetUpPopUpPositionNotifications();
+    SetUpPopupPositionNotifications();
+
+    mCopyPastePopup.actor.SetPosition( mCopyPastePopup.position );
+  }
+
+  void PopupRelayoutComplete( Actor actor )
+  {
+    // Size negotiation for CopyPastePopup complete so can get the size and constrain position within bounding box.
+    mCopyPastePopup.actor.OnRelayoutSignal().Disconnect( this, &Decorator::Impl::PopupRelayoutComplete  );
 
-    mCopyPastePopup.SetPosition( popupPosition ); //todo grabhandle(cursor) or selection handle positions to be used
+    DeterminePositionPopup();
   }
 
   void CreateCursor( ImageActor& cursor, const Vector4& color )
@@ -477,8 +518,6 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( !mActiveLayer )
     {
-      Actor parent = mTextControlParent.Self();
-
       mActiveLayer = Layer::New();
 #ifdef DECORATOR_DEBUG
       mActiveLayer.SetName ( "ActiveLayerActor" );
@@ -488,7 +527,8 @@ struct Decorator::Impl : public ConnectionTracker
       mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
       mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
 
-      parent.Add( mActiveLayer );
+      // Add the active layer telling the controller it doesn't need clipping.
+      mController.AddDecoration( mActiveLayer, false );
     }
 
     mActiveLayer.RaiseToTop();
@@ -549,7 +589,11 @@ struct Decorator::Impl : public ConnectionTracker
     {
       if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
+        mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_RELEASED );
+      }
+      if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] )
+      {
+        mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_PRESSED );
       }
 
       primary.actor = ImageActor::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
@@ -565,8 +609,9 @@ struct Decorator::Impl : public ConnectionTracker
       primary.grabArea.SetName("SelectionHandleOneGrabArea");
 #endif
       primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+      primary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+      primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
       primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
-      primary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
 
       mTapDetector.Attach( primary.grabArea );
       mPanGestureDetector.Attach( primary.grabArea );
@@ -581,7 +626,11 @@ struct Decorator::Impl : public ConnectionTracker
     {
       if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
+        mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO_RELEASED );
+      }
+      if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] )
+      {
+        mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO_PRESSED );
       }
 
       secondary.actor = ImageActor::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
@@ -597,8 +646,9 @@ struct Decorator::Impl : public ConnectionTracker
       secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
 #endif
       secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+      secondary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+      secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
       secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
-      secondary.grabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
 
       mTapDetector.Attach( secondary.grabArea );
       mPanGestureDetector.Attach( secondary.grabArea );
@@ -627,11 +677,12 @@ struct Decorator::Impl : public ConnectionTracker
       mHighlightMeshActor.SetName( "HighlightMeshActor" );
 #endif
       mHighlightMeshActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-      mHighlightMeshActor.SetPosition( 0.0f, 0.0f, DISPLAYED_HIGHLIGHT_Z_OFFSET );
 
-      Actor parent = mTextControlParent.Self();
-      parent.Add( mHighlightMeshActor );
+      // Add the highlight box telling the controller it needs clipping.
+      mController.AddDecoration( mHighlightMeshActor, true );
     }
+
+    mHighlightMeshActor.SetPosition( mHighlightPosition.x, mHighlightPosition.y, DISPLAYED_HIGHLIGHT_Z_OFFSET );
     */
   }
 
@@ -753,13 +804,16 @@ struct Decorator::Impl : public ConnectionTracker
     if( Gesture::Started    == gesture.state ||
         Gesture::Continuing == gesture.state )
     {
+      Vector2 targetSize;
+      mController.GetTargetSize( targetSize );
+
       if( x < mScrollThreshold )
       {
         mScrollDirection = SCROLL_RIGHT;
         mHandleScrolling = type;
         StartScrollTimer();
       }
-      else if( x > mTextControlParent.Self().GetTargetSize().width - mScrollThreshold )
+      else if( x > targetSize.width - mScrollThreshold )
       {
         mScrollDirection = SCROLL_LEFT;
         mHandleScrolling = type;
@@ -769,23 +823,41 @@ struct Decorator::Impl : public ConnectionTracker
       {
         mHandleScrolling = HANDLE_TYPE_COUNT;
         StopScrollTimer();
-        mObserver.HandleEvent( type, HANDLE_PRESSED, x, y );
+        mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
       }
     }
     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();
-        mObserver.HandleEvent( type, HANDLE_STOP_SCROLLING, x, y );
+        mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
       }
       else
       {
-        mObserver.HandleEvent( type, HANDLE_RELEASED, x, y );
+        mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
       }
-      handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+
+      if( GRAB_HANDLE == type )
+      {
+        handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+      }
+      else
+      {
+        HandleType selectionHandleType = type;
+
+        if( mSwapSelectionHandles != handle.flipped )
+        {
+          selectionHandleType = ( LEFT_SELECTION_HANDLE == type ) ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE;
+        }
+
+        handle.actor.SetImage( mHandleImages[selectionHandleType][HANDLE_IMAGE_RELEASED] );
+      }
+      handle.pressed = false;
     }
   }
 
@@ -817,15 +889,23 @@ struct Decorator::Impl : public ConnectionTracker
     {
       const TouchPoint& point = event.GetPoint(0);
 
-      if( TouchPoint::Down == point.state &&
-          mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] )
+      if( TouchPoint::Down == point.state )
       {
-        mHandle[GRAB_HANDLE].actor.SetImage( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] );
+        mHandle[GRAB_HANDLE].pressed = true;
+        Image imagePressed = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED];
+        if( imagePressed )
+        {
+          mHandle[GRAB_HANDLE].actor.SetImage( imagePressed );
+        }
       }
-      else if( TouchPoint::Up == point.state &&
-               mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
+      else if( TouchPoint::Up == point.state )
       {
-        mHandle[GRAB_HANDLE].actor.SetImage( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
+        mHandle[GRAB_HANDLE].pressed = false;
+        Image imageReleased = mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED];
+        if( imageReleased )
+        {
+          mHandle[GRAB_HANDLE].actor.SetImage( imageReleased );
+        }
       }
     }
 
@@ -833,16 +913,68 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
-  bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
+  bool OnHandleOneTouched( Actor actor, const TouchEvent& event )
   {
-    // TODO
+    // Switch between pressed/release selection handle images
+    if( event.GetPointCount() > 0 &&
+        mHandle[LEFT_SELECTION_HANDLE].actor )
+    {
+      const TouchPoint& point = event.GetPoint(0);
+
+      const bool flip = mSwapSelectionHandles != mHandle[LEFT_SELECTION_HANDLE].flipped;
+      if( TouchPoint::Down == point.state )
+      {
+        mHandle[LEFT_SELECTION_HANDLE].pressed = true;
+        Image imagePressed = mHandleImages[flip ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED];
+        if( imagePressed )
+        {
+          mHandle[LEFT_SELECTION_HANDLE].actor.SetImage( imagePressed );
+        }
+      }
+      else if( TouchPoint::Up == point.state )
+      {
+        mHandle[LEFT_SELECTION_HANDLE].pressed = false;
+        Image imageReleased = mHandleImages[flip ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED];
+        if( imageReleased )
+        {
+          mHandle[LEFT_SELECTION_HANDLE].actor.SetImage( imageReleased );
+        }
+      }
+    }
+
     // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
     return true;
   }
 
-  bool OnHandleTwoTouched( Actor actor, const TouchEvent& touch )
+  bool OnHandleTwoTouched( Actor actor, const TouchEvent& event )
   {
-    // TODO
+    // Switch between pressed/release selection handle images
+    if( event.GetPointCount() > 0 &&
+        mHandle[RIGHT_SELECTION_HANDLE].actor )
+    {
+      const TouchPoint& point = event.GetPoint(0);
+
+      const bool flip = mSwapSelectionHandles != mHandle[RIGHT_SELECTION_HANDLE].flipped;
+      if( TouchPoint::Down == point.state )
+      {
+        Image imagePressed = mHandleImages[flip ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_PRESSED];
+        mHandle[RIGHT_SELECTION_HANDLE].pressed = true;
+        if( imagePressed )
+        {
+          mHandle[RIGHT_SELECTION_HANDLE].actor.SetImage( imagePressed );
+        }
+      }
+      else if( TouchPoint::Up == point.state )
+      {
+        Image imageReleased = mHandleImages[flip ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED];
+        mHandle[RIGHT_SELECTION_HANDLE].pressed = false;
+        if( imageReleased )
+        {
+          mHandle[RIGHT_SELECTION_HANDLE].actor.SetImage( imageReleased );
+        }
+      }
+    }
+
     // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
     return true;
   }
@@ -884,11 +1016,11 @@ struct Decorator::Impl : public ConnectionTracker
     // if can't be positioned above, then position below row.
     alternativeYPosition = AlternatePopUpPositionRelativeToCursor();
 
-    mCopyPastePopup.SetY( alternativeYPosition );
+    mCopyPastePopup.actor.SetY( alternativeYPosition );
   }
 
 
-  void SetUpPopUpPositionNotifications( )
+  void SetUpPopupPositionNotifications( )
   {
     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
 
@@ -897,11 +1029,11 @@ struct Decorator::Impl : public ConnectionTracker
     Vector4 worldCoordinatesBoundingBox;
     LocalToWorldCoordinatesBoundingBox( mBoundingBox, worldCoordinatesBoundingBox );
 
-    float popupHeight = mCopyPastePopup.GetRelayoutSize( Dimension::HEIGHT);
+    float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT);
 
-    PropertyNotification verticalExceedNotification = mCopyPastePopup.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
-                                                      OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight/2,
-                                                                        worldCoordinatesBoundingBox.w - popupHeight/2 ) );
+    PropertyNotification verticalExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                      OutsideCondition( worldCoordinatesBoundingBox.y + popupHeight * 0.5f,
+                                                                        worldCoordinatesBoundingBox.w - popupHeight * 0.5f ) );
 
     verticalExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesVerticalBoundary );
   }
@@ -938,6 +1070,34 @@ struct Decorator::Impl : public ConnectionTracker
     }
 
     requiredPopupPosition.x = requiredPopupPosition.x + xOffSetToKeepWithinBounds;
+
+    // Prevent pixel mis-alignment by rounding down.
+    requiredPopupPosition.x = static_cast<int>( requiredPopupPosition.x );
+    requiredPopupPosition.y = static_cast<int>( requiredPopupPosition.y );
+
+  }
+
+  void FlipSelectionHandleImages()
+  {
+    SetupTouchEvents();
+
+    CreateSelectionHandles();
+
+    HandleImpl& leftHandle = mHandle[LEFT_SELECTION_HANDLE];
+    HandleImpl& rightHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    const HandleImageType leftImageType = leftHandle.pressed ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED;
+    const HandleImageType rightImageType = rightHandle.pressed ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED;
+    const bool leftFlipped = mSwapSelectionHandles != leftHandle.flipped;
+    const bool rightFlipped = mSwapSelectionHandles != rightHandle.flipped;
+
+    leftHandle.actor.SetImage( leftFlipped ? mHandleImages[RIGHT_SELECTION_HANDLE][leftImageType] : mHandleImages[LEFT_SELECTION_HANDLE][leftImageType] );
+
+    leftHandle.actor.SetAnchorPoint( leftFlipped ? AnchorPoint::TOP_LEFT : AnchorPoint::TOP_RIGHT );
+
+    rightHandle.actor.SetImage( rightFlipped ? mHandleImages[LEFT_SELECTION_HANDLE][rightImageType] : mHandleImages[RIGHT_SELECTION_HANDLE][rightImageType] );
+
+    rightHandle.actor.SetAnchorPoint( rightFlipped ? AnchorPoint::TOP_RIGHT : AnchorPoint::TOP_LEFT );
   }
 
   void SetScrollThreshold( float threshold )
@@ -961,6 +1121,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.
    *
@@ -1000,17 +1170,16 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( HANDLE_TYPE_COUNT != mHandleScrolling )
     {
-      mObserver.HandleEvent( mHandleScrolling,
-                             HANDLE_SCROLLING,
-                             mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
-                             0.f );
+      mController.DecorationEvent( mHandleScrolling,
+                                   HANDLE_SCROLLING,
+                                   mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
+                                   0.f );
     }
 
     return true;
   }
 
-  Internal::Control&  mTextControlParent;
-  Observer&           mObserver;
+  ControllerInterface& mController;
 
   TapGestureDetector  mTapDetector;
   PanGestureDetector  mPanGestureDetector;
@@ -1021,7 +1190,10 @@ struct Decorator::Impl : public ConnectionTracker
   //ImageActor          mPrimaryCursor;
   //ImageActor          mSecondaryCursor;
   //MeshActor           mHighlightMeshActor;        ///< Mesh Actor to display highlight
-  TextSelectionPopup  mCopyPastePopup;
+
+  PopupImpl           mCopyPastePopup;
+  TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
+  TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
 
   Image               mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
   Image               mCursorImage;
@@ -1035,6 +1207,7 @@ struct Decorator::Impl : public ConnectionTracker
 
   Rect<int>           mBoundingBox;
   Vector4             mHighlightColor;            ///< Color of the highlight
+  Vector2             mHighlightPosition;         ///< The position of the highlight actor.
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
@@ -1044,17 +1217,20 @@ 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( Internal::Control& parent, Observer& observer )
+DecoratorPtr Decorator::New( ControllerInterface& controller,
+                             TextSelectionPopupCallbackInterface& callbackInterface )
 {
-  return DecoratorPtr( new Decorator(parent, observer) );
+  return DecoratorPtr( new Decorator( controller,
+                                      callbackInterface ) );
 }
 
 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
@@ -1206,6 +1382,18 @@ void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& h
   height = handle.lineHeight;
 }
 
+const Vector2& Decorator::GetPosition( HandleType handleType ) const
+{
+  return mImpl->mHandle[handleType].position;
+}
+
+void Decorator::SwapSelectionHandlesEnabled( bool enable )
+{
+  mImpl->mSwapSelectionHandles = enable;
+
+  mImpl->FlipSelectionHandleImages();
+}
+
 void Decorator::AddHighlight( float x1, float y1, float x2, float y2 )
 {
   mImpl->mHighlightQuadList.push_back( QuadCoordinates(x1, y1, x2, y2) );
@@ -1214,6 +1402,7 @@ void Decorator::AddHighlight( float x1, float y1, float x2, float y2 )
 void Decorator::ClearHighlights()
 {
   mImpl->mHighlightQuadList.clear();
+  mImpl->mHighlightPosition = Vector2::ZERO;
 }
 
 void Decorator::SetHighlightColor( const Vector4& color )
@@ -1236,6 +1425,16 @@ bool Decorator::IsPopupActive() const
   return mImpl->mActiveCopyPastePopup ;
 }
 
+void Decorator::SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask )
+{
+   mImpl->mEnabledPopupButtons = enabledButtonsBitMask;
+}
+
+TextSelectionPopup::Buttons& Decorator::GetEnabledPopupButtons()
+{
+  return mImpl->mEnabledPopupButtons;
+}
+
 /** Scroll **/
 
 void Decorator::SetScrollThreshold( float threshold )
@@ -1258,15 +1457,21 @@ float Decorator::GetScrollSpeed() const
   return mImpl->GetScrollSpeed();
 }
 
+void Decorator::NotifyEndOfScroll()
+{
+  mImpl->NotifyEndOfScroll();
+}
+
 Decorator::~Decorator()
 {
   delete mImpl;
 }
 
-Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
+Decorator::Decorator( ControllerInterface& controller,
+                      TextSelectionPopupCallbackInterface& callbackInterface )
 : mImpl( NULL )
 {
-  mImpl = new Decorator::Impl( parent, observer );
+  mImpl = new Decorator::Impl( controller, callbackInterface );
 }
 
 } // namespace Text
index e341e2b..f38c467 100644 (file)
 #include <dali/public-api/math/rect.h>
 #include <dali/public-api/math/vector2.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
 namespace Dali
 {
 
+class Actor;
 class Image;
 class Vector2;
 class Vector4;
@@ -34,6 +38,8 @@ class Vector4;
 namespace Toolkit
 {
 
+class TextSelectionPopupCallbackInterface;
+
 namespace Internal
 {
 class Control;
@@ -98,26 +104,40 @@ enum HandleType
  *
  * Selection handles will be flipped around to ensure they do not exceed the Decoration Bounding Box. ( Stay visible ).
  *
- * Decorator components forward input events to a controller class through an observer interface.
+ * Decorator components forward input events to a controller class through an interface.
  * The controller is responsible for selecting which components are active.
  */
 class Decorator : public RefObject
 {
 public:
 
-  class Observer
+  class ControllerInterface
   {
   public:
 
     /**
      * @brief Constructor.
      */
-    Observer() {};
+    ControllerInterface() {};
 
     /**
      * @brief Virtual destructor.
      */
-    virtual ~Observer() {};
+    virtual ~ControllerInterface() {};
+
+    /**
+     * @brief An input event from one of the handles.
+     *
+     * @param[out] targetSize The Size of the UI control the decorator is adding it's decorations to.
+     */
+    virtual void GetTargetSize( Vector2& targetSize ) = 0;
+
+    /**
+     * @brief Add a decoration to the parent UI control.
+     *
+     * @param[in] decoration The actor displaying a decoration.
+     */
+    virtual void AddDecoration( Actor& actor, bool needsClipping ) = 0;
 
     /**
      * @brief An input event from one of the handles.
@@ -127,17 +147,19 @@ public:
      * @param[in] x The x position relative to the top-left of the parent control.
      * @param[in] y The y position relative to the top-left of the parent control.
      */
-    virtual void HandleEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
+    virtual void DecorationEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
   };
 
   /**
    * @brief Create a new instance of a Decorator.
    *
-   * @param[in] parent Decorations will be added to this parent control.
-   * @param[in] observer A class which receives input events from Decorator components.
+   * @param[in] controller The controller which receives input events from Decorator components.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   *
    * @return A pointer to a new Decorator.
    */
-  static DecoratorPtr New( Dali::Toolkit::Internal::Control& parent, Observer& observer );
+  static DecoratorPtr New( ControllerInterface& controller,
+                           TextSelectionPopupCallbackInterface& callbackInterface );
 
   /**
    * @brief Set the bounding box which handles, popup and similar decorations will not exceed.
@@ -341,6 +363,23 @@ public:
   void GetPosition( HandleType handleType, float& x, float& y, float& lineHeight ) const;
 
   /**
+   * @brief Retrieves the position of a selection handle.
+   *
+   * @param[in] handleType The handle to get.
+   *
+   * @return The position of the selection handle relative to the top-left of the parent control.
+   */
+  const Vector2& GetPosition( HandleType handleType ) const;
+
+  /**
+   * @brief Swaps the selection handle's images.
+   *
+   * This method is called by the text controller to swap the handles
+   * when the start index is bigger than the end one.
+   */
+  void SwapSelectionHandlesEnabled( bool enable );
+
+  /**
    * @brief Adds a quad to the existing selection highlights.
    *
    * @param[in] x1 The top-left x position.
@@ -383,6 +422,18 @@ public:
   bool IsPopupActive() const;
 
   /**
+   * @brief Set a bit mask of the buttons to be shown by Popup
+   * @param[in] enabledButtonsBitMask from TextSelectionPopup::Buttons enum
+   */
+  void SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask );
+
+  /**
+   * @brief Get the current bit mask of buttons to be shown by Popup
+   * @return bitmask of TextSelectionPopup::Buttons
+   */
+  TextSelectionPopup::Buttons& GetEnabledPopupButtons();
+
+  /**
    * @brief Sets the scroll threshold.
    *
    * It defines a square area inside the control, close to the edge.
@@ -416,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:
 
@@ -440,10 +482,11 @@ private:
 
   /**
    * @brief Private constructor.
-   * @param[in] parent Decorations will be added to this parent control.
-   * @param[in] observer A class which receives input events from Decorator components.
+   * @param[in] controller The controller which receives input events from Decorator components.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
    */
-  Decorator(Dali::Toolkit::Internal::Control& parent, Observer& observer );
+  Decorator( ControllerInterface& controller,
+             TextSelectionPopupCallbackInterface& callbackInterface );
 
   // Undefined
   Decorator( const Decorator& handle );
index d1c38e2..e75009d 100644 (file)
@@ -60,7 +60,8 @@ struct LineLayout
     numberOfGlyphs( 0u ),
     numberOfCharacters( 0u ),
     length( 0.f ),
-    widthAdvanceDiff( 0.f ),
+    extraBearing( 0.f ),
+    extraWidth( 0.f ),
     wsLengthEndOfLine( 0.f ),
     ascender( 0.f ),
     descender( MAX_FLOAT )
@@ -76,7 +77,8 @@ struct LineLayout
     numberOfGlyphs = 0u;
     numberOfCharacters = 0u;
     length = 0.f;
-    widthAdvanceDiff = 0.f;
+    extraBearing = 0.f;
+    extraWidth = 0.f;
     wsLengthEndOfLine = 0.f;
     ascender = 0.f;
     descender = MAX_FLOAT;
@@ -86,8 +88,9 @@ struct LineLayout
   CharacterIndex characterIndex;     ///< Index of the first character to be laid-out.
   Length         numberOfGlyphs;     ///< The number of glyph which fit in one line.
   Length         numberOfCharacters; ///< The number of characters which fit in one line.
-  float          length;             ///< The length of the glyphs which fit in one line.
-  float          widthAdvanceDiff;   ///< The difference between the xBearing + width and the advance of the last glyph.
+  float          length;             ///< The addition of the advance metric of all the glyphs which fit in one line.
+  float          extraBearing;       ///< The extra width to be added to the line's length when the bearing of the first glyph is negative.
+  float          extraWidth;         ///< The extra width to be added to the line's length when the bearing + width of the last glyph is greater than the advance.
   float          wsLengthEndOfLine;  ///< The length of the white spaces at the end of the line.
   float          ascender;           ///< The maximum ascender of all fonts in the line.
   float          descender;          ///< The minimum descender of all fonts in the line.
@@ -146,7 +149,6 @@ struct LayoutEngine::Impl
       lineLayout.length += lineLayout.wsLengthEndOfLine;
 
       lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
-      lineLayout.widthAdvanceDiff = tmpLineLayout.widthAdvanceDiff;
     }
     else
     {
@@ -167,12 +169,23 @@ struct LayoutEngine::Impl
   /**
    * Retrieves the line layout for a given box width.
    *
+   * @note This method lais out text as it were left to right. At this point is not possible to reorder the line
+   *       because the number of characters of the line is not known (one of the responsabilities of this method
+   *       is calculate that). Due to glyph's 'x' bearing, width and advance, when right to left or mixed right to left
+   *       and left to right text is laid out, it can be small differences in the line length. One solution is to
+   *       reorder and re-lay out the text after this method and add or remove one extra glyph if needed. However,
+   *       this method calculates which are the first and last glyphs of the line (the ones that causes the
+   *       differences). This is a good point to check if there is problems with the text exceeding the boundaries
+   *       of the control when there is right to left text.
+   *
    * @param[in] parameters The layout parameters.
    * @param[out] lineLayout The line layout.
+   * @param[in,out] paragraphDirection in: the current paragraph's direction, out: the next paragraph's direction. Is set after a must break.
    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
    */
   void GetLineLayoutForBox( const LayoutParameters& parameters,
                             LineLayout& lineLayout,
+                            CharacterDirection& paragraphDirection,
                             bool completelyFill )
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n" );
@@ -184,38 +197,26 @@ struct LayoutEngine::Impl
     const GlyphIndex lastGlyphIndex = parameters.totalNumberOfGlyphs - 1u;
 
     // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
-    // In the case the line starts with a right to left character the bearing needs to be substracted to the line length.
+    // In the case the line starts with a right to left character, if the width is longer than the advance,
+    // the difference needs to be added to the line length.
     const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + lineLayout.glyphIndex );
-    float initialHorizontalBearing = glyphInfo.xBearing;
 
+    // Set the direction of the first character of the line.
     lineLayout.characterIndex = *( parameters.glyphsToCharactersBuffer + lineLayout.glyphIndex );
     const CharacterDirection firstCharacterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + lineLayout.characterIndex );
+    CharacterDirection previousCharacterDirection = firstCharacterDirection;
 
-    if( RTL == firstCharacterDirection )
-    {
-      initialHorizontalBearing = -initialHorizontalBearing;
+    const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+    float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
 
-      if( 0.f < glyphInfo.xBearing )
-      {
-        tmpLineLayout.length = glyphInfo.xBearing;
-        initialHorizontalBearing = 0.f;
-      }
-    }
-    else
-    {
-      if( 0.f > glyphInfo.xBearing )
-      {
-        tmpLineLayout.length = -glyphInfo.xBearing;
-        initialHorizontalBearing = 0.f;
-      }
-    }
+    float tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+
+    tmpLineLayout.length += 1.f; // Added one unit to give some space to the cursor.
 
     // Calculate the line height if there is no characters.
     FontId lastFontId = glyphInfo.fontId;
     UpdateLineHeight( lastFontId, tmpLineLayout );
 
-    const float boundingBoxWidth = parameters.boundingBox.width - initialHorizontalBearing;
-
     bool oneWordLaidOut = false;
 
     for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
@@ -253,7 +254,11 @@ struct LayoutEngine::Impl
 
       // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
       const float previousTmpLineLength = tmpLineLayout.length;
-      const float previousTmpWidthAdvanceDiff = tmpLineLayout.widthAdvanceDiff;
+      const float previousTmpExtraBearing = tmpExtraBearing;
+      const float previousTmpExtraWidth = tmpExtraWidth;
+
+      // Get the character's direction.
+      const CharacterDirection characterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + characterFirstIndex );
 
       // Increase the accumulated length.
       if( isWhiteSpace )
@@ -265,13 +270,82 @@ struct LayoutEngine::Impl
       {
         // Add as well any previous white space length.
         tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphInfo.advance;
-        if( RTL == firstCharacterDirection )
+
+        // An extra space may be added to the line for the first and last glyph of the line.
+        // If the bearing of the first glyph is negative, its positive value needs to be added.
+        // If the bearing plus the width of the last glyph is greater than the advance, the difference
+        // needs to be added.
+
+        if( characterDirection == paragraphDirection )
         {
-          tmpLineLayout.widthAdvanceDiff = -glyphInfo.xBearing;
+          if( RTL == characterDirection )
+          {
+            //       <--
+            // |   Rrrrr|
+            // or
+            // |  Rllrrr|
+            // or
+            // |lllrrrrr|
+            // |     Rll|
+            //
+
+            tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+          }
+          else // LTR
+          {
+            //  -->
+            // |lllL    |
+            // or
+            // |llrrL   |
+            // or
+            // |lllllrrr|
+            // |rrL     |
+            //
+
+            const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+            tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+          }
         }
         else
         {
-          tmpLineLayout.widthAdvanceDiff = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+          if( characterDirection != previousCharacterDirection )
+          {
+            if( RTL == characterDirection )
+            {
+              //  -->
+              // |lllR    |
+
+              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+              tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+            }
+            else // LTR
+            {
+              //       <--
+              // |   Lrrrr|
+
+              tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+            }
+          }
+          else if( characterDirection == firstCharacterDirection )
+          {
+            if( RTL == characterDirection )
+            {
+              //  -->
+              // |llllllrr|
+              // |Rr      |
+
+              tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+            }
+            else // LTR
+            {
+              //       <--
+              // |llllrrrr|
+              // |     llL|
+
+              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+              tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+            }
+          }
         }
 
         // Clear the white space length at the end of the line.
@@ -280,7 +354,7 @@ struct LayoutEngine::Impl
 
       // Check if the accumulated length fits in the width of the box.
       if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
-          ( lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpLineLayout.widthAdvanceDiff > boundingBoxWidth ) )
+          ( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
       {
         // Current word does not fit in the box's width.
         if( !oneWordLaidOut || completelyFill )
@@ -293,7 +367,8 @@ struct LayoutEngine::Impl
             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
             --tmpLineLayout.numberOfGlyphs;
             tmpLineLayout.length = previousTmpLineLength;
-            tmpLineLayout.widthAdvanceDiff = previousTmpWidthAdvanceDiff;
+            tmpExtraBearing = previousTmpExtraBearing;
+            tmpExtraWidth = previousTmpExtraWidth;
           }
 
           // Add part of the word to the line layout.
@@ -303,7 +378,12 @@ struct LayoutEngine::Impl
         {
           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Current word does not fit.\n" );
         }
-        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
+
+        lineLayout.extraBearing = tmpExtraBearing;
+        lineLayout.extraWidth = tmpExtraWidth;
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox.\n" );
+
         return;
       }
 
@@ -313,6 +393,16 @@ struct LayoutEngine::Impl
         // Must break the line. Update the line layout and return.
         MergeLineLayout( lineLayout, tmpLineLayout );
 
+        // Set the next paragraph's direction.
+        if( !isLastGlyph &&
+            ( NULL != parameters.characterDirectionBuffer ) )
+        {
+          paragraphDirection = *( parameters.characterDirectionBuffer + 1u + characterLastIndex );
+        }
+
+        lineLayout.extraBearing = tmpExtraBearing;
+        lineLayout.extraWidth = tmpExtraWidth;
+
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
         return;
@@ -338,7 +428,13 @@ struct LayoutEngine::Impl
         UpdateLineHeight( glyphInfo.fontId, tmpLineLayout );
         lastFontId = glyphInfo.fontId;
       }
+
+      previousCharacterDirection = characterDirection;
     }
+
+    lineLayout.extraBearing = tmpExtraBearing;
+    lineLayout.extraWidth = tmpExtraWidth;
+
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
   }
 
@@ -352,13 +448,10 @@ struct LayoutEngine::Impl
     // Check if the x bearing of the first character is negative.
     // If it has a negative x bearing, it will exceed the boundaries of the actor,
     // so the penX position needs to be moved to the right.
-    float penX = 0.f;
 
     const GlyphInfo& glyph = *glyphsBuffer;
-    if( 0.f > glyph.xBearing )
-    {
-      penX = -glyph.xBearing;
-    }
+    float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
+    penX += 1.f; // Added one unit to give some space to the cursor.
 
     for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
     {
@@ -380,14 +473,20 @@ struct LayoutEngine::Impl
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
 
+    // Set the first paragraph's direction.
+    CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
+
     float penY = 0.f;
     for( GlyphIndex index = 0u; index < layoutParameters.totalNumberOfGlyphs; )
     {
+      CharacterDirection currentParagraphDirection = paragraphDirection;
+
       // Get the layout for the line.
       LineLayout layout;
       layout.glyphIndex = index;
       GetLineLayoutForBox( layoutParameters,
                            layout,
+                           paragraphDirection,
                            false );
 
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
@@ -411,7 +510,7 @@ struct LayoutEngine::Impl
       if( mEllipsisEnabled &&
           ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
             ( ( mLayout == SINGLE_LINE_BOX ) &&
-              ( layout.length + layout.widthAdvanceDiff > layoutParameters.boundingBox.width ) ) ) )
+              ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) ) )
       {
         // Do not layout more lines if ellipsis is enabled.
 
@@ -439,15 +538,16 @@ struct LayoutEngine::Impl
 
         GetLineLayoutForBox( layoutParameters,
                              ellipsisLayout,
+                             currentParagraphDirection,
                              true );
 
         lineRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
         lineRun.characterRun.characterIndex = ellipsisLayout.characterIndex;
         lineRun.characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
-        lineRun.width = layoutParameters.boundingBox.width;
+        lineRun.width = ellipsisLayout.length;
+        lineRun.extraLength =  ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f;
         lineRun.ascender = ellipsisLayout.ascender;
         lineRun.descender = ellipsisLayout.descender;
-        lineRun.extraLength = ellipsisLayout.wsLengthEndOfLine > 0.f ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.widthAdvanceDiff : 0.f;
         lineRun.ellipsis = true;
 
         actualSize.width = layoutParameters.boundingBox.width;
@@ -473,15 +573,34 @@ struct LayoutEngine::Impl
       }
       else
       {
+        const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
+
         LineRun lineRun;
         lineRun.glyphIndex = index;
         lineRun.numberOfGlyphs = layout.numberOfGlyphs;
         lineRun.characterRun.characterIndex = layout.characterIndex;
         lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
-        lineRun.width = layout.length + layout.widthAdvanceDiff;
+        if( isLastLine )
+        {
+          const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
+          if( MULTI_LINE_BOX == mLayout )
+          {
+            lineRun.width = ( width > layoutParameters.boundingBox.width ) ? layoutParameters.boundingBox.width : width;
+          }
+          else
+          {
+            lineRun.width = width;
+          }
+
+          lineRun.extraLength = 0.f;
+        }
+        else
+        {
+          lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
+          lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
+        }
         lineRun.ascender = layout.ascender;
         lineRun.descender = layout.descender;
-        lineRun.extraLength = layout.wsLengthEndOfLine > 0.f ? layout.wsLengthEndOfLine - layout.widthAdvanceDiff : 0.f;
         lineRun.direction = false;
         lineRun.ellipsis = false;
 
@@ -508,6 +627,7 @@ struct LayoutEngine::Impl
     }
 
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
+
     return true;
   }
 
@@ -519,12 +639,11 @@ struct LayoutEngine::Impl
     {
       const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer + lineIndex );
 
-      float penX = 0.f;
-
       const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
 
-      penX = -glyph.xBearing;
+      float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
+      penX += 1.f; // Added one unit to give some space to the cursor.
 
       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
 
@@ -556,76 +675,36 @@ struct LayoutEngine::Impl
     }
   }
 
-  void Align( const LayoutParameters& layoutParameters,
-              const Size& layoutSize,
-              const Vector<LineRun>& lines,
-              Vector<Vector2>& glyphPositions )
+  void Align( const Size& layoutSize,
+              Vector<LineRun>& lines )
   {
-    Vector2* glyphPositionsBuffer = glyphPositions.Begin();
-
     // Traverse all lines and align the glyphs.
-    // LayoutParameters contains bidirectional info for those lines with
-    // right to left text, this info includes the paragraph's direction.
 
-    LineIndex bidiLineIndex = 0u;
-    for( Vector<LineRun>::ConstIterator it = lines.Begin(), endIt = lines.End();
+    for( Vector<LineRun>::Iterator it = lines.Begin(), endIt = lines.End();
          it != endIt;
          ++it )
     {
-      const LineRun& line = *it;
-
-      // 1) Get the paragrap's direction.
-      bool paragraphDirection = false;
-
-      // Check if there is any right to left line.
-      if( ( NULL != layoutParameters.lineBidirectionalInfoRunsBuffer ) &&
-          ( bidiLineIndex < layoutParameters.numberOfBidirectionalInfoRuns ) )
-      {
-        const BidirectionalLineInfoRun* bidiLine = layoutParameters.lineBidirectionalInfoRunsBuffer + bidiLineIndex;
-
-        // Get the right to left line that match with current line.
-        while( ( line.characterRun.characterIndex > bidiLine->characterRun.characterIndex ) &&
-               ( bidiLineIndex < layoutParameters.numberOfBidirectionalInfoRuns ) )
-        {
-          ++bidiLineIndex;
-          bidiLine = layoutParameters.lineBidirectionalInfoRunsBuffer + bidiLineIndex;
-        }
-
-        if( line.characterRun.characterIndex == bidiLine->characterRun.characterIndex )
-        {
-          paragraphDirection = bidiLine->direction;
-        }
-      }
-
-      // 2) Calculate the alignment offset accordingly with the align option,
-      //    the box width, line length, and the paragraphs direction.
-      float alignOffset = CalculateHorizontalAlignment( layoutSize.width,
-                                                        line.width,
-                                                        line.extraLength,
-                                                        paragraphDirection );
-
-      // 3) Traverse all glyphs and update the 'x' position.
-      for( GlyphIndex index = line.glyphIndex,
-             endIndex = line.glyphIndex + line.numberOfGlyphs;
-           index < endIndex;
-           ++index )
-      {
-        Vector2& position = *( glyphPositionsBuffer + index );
-
-        position.x += alignOffset;
-      }
+      LineRun& line = *it;
+      const bool isLastLine = lines.End() == it + 1u;
+
+      // Calculate the alignment offset accordingly with the align option,
+      // the box width, line length, and the paragraphs direction.
+      CalculateHorizontalAlignment( layoutSize.width,
+                                    line,
+                                    isLastLine );
     }
   }
 
-  float CalculateHorizontalAlignment( float boxWidth,
-                                      float lineLength,
-                                      float extraLength,
-                                      bool paragraphDirection )
+  void CalculateHorizontalAlignment( float boxWidth,
+                                     LineRun& line,
+                                     bool isLastLine )
   {
-    float offset = 0.f;
+    line.alignmentOffset = 0.f;
+    const bool isRTL = RTL == line.direction;
+    float lineLength = line.width;
 
     HorizontalAlignment alignment = mHorizontalAlignment;
-    if( paragraphDirection &&
+    if( isRTL &&
         ( HORIZONTAL_ALIGN_CENTER != alignment ) )
     {
       if( HORIZONTAL_ALIGN_BEGIN == alignment )
@@ -642,29 +721,69 @@ struct LayoutEngine::Impl
     {
       case HORIZONTAL_ALIGN_BEGIN:
       {
-        offset = 0.f;
+        line.alignmentOffset = 0.f;
+
+        if( isRTL )
+        {
+          // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+          line.alignmentOffset -= line.extraLength;
+
+          if( isLastLine )
+          {
+            line.alignmentOffset += std::min( line.extraLength, boxWidth - lineLength );
+          }
+        }
         break;
       }
       case HORIZONTAL_ALIGN_CENTER:
       {
-        offset = 0.5f * ( boxWidth - lineLength );
-        const int intOffset = static_cast<int>( offset ); // try to avoid pixel alignment.
-        offset = static_cast<float>( intOffset );
+        if( isLastLine && !isRTL )
+        {
+          lineLength += line.extraLength;
+          if( lineLength > boxWidth )
+          {
+            lineLength = boxWidth;
+            line.alignmentOffset = 0.f;
+            break;
+          }
+        }
+
+        line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
+
+        if( isRTL )
+        {
+          line.alignmentOffset -= line.extraLength;
+
+          if( isLastLine )
+          {
+            line.alignmentOffset += 0.5f * std::min( line.extraLength, boxWidth - lineLength );
+          }
+        }
+
+        line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
         break;
       }
       case HORIZONTAL_ALIGN_END:
       {
-        offset = boxWidth - lineLength;
+        if( isLastLine && !isRTL )
+        {
+          lineLength += line.extraLength;
+          if( lineLength > boxWidth )
+          {
+            line.alignmentOffset = 0.f;
+            break;
+          }
+        }
+
+        if( isRTL )
+        {
+          lineLength += line.extraLength;
+        }
+
+        line.alignmentOffset = boxWidth - lineLength;
         break;
       }
     }
-
-    if( paragraphDirection )
-    {
-      offset -= extraLength;
-    }
-
-    return offset;
   }
 
   LayoutEngine::Layout mLayout;
@@ -745,15 +864,11 @@ void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParam
                                    glyphPositions );
 }
 
-void LayoutEngine::Align( const LayoutParameters& layoutParameters,
-                          const Size& layoutSize,
-                          const Vector<LineRun>& lines,
-                          Vector<Vector2>& glyphPositions )
+void LayoutEngine::Align( const Size& layoutSize,
+                          Vector<LineRun>& lines )
 {
-  mImpl->Align( layoutParameters,
-                layoutSize,
-                lines,
-                glyphPositions );
+  mImpl->Align( layoutSize,
+                lines );
 }
 
 } // namespace Text
index 42ff1aa..e48de90 100644 (file)
@@ -158,15 +158,11 @@ public:
   /**
    * @brief Aligns the laid out lines.
    *
-   * @param[in] layoutParameters The parameters needed to layout the text.
    * @param[in] layoutSize The size of the laid out the text.
-   * @param[in] lines The laid-out lines.
-   * @param[in,out] glyphPositions The positions of all the glyphs.
+   * @param[in,out] lines The laid-out lines.
    */
-  void Align( const LayoutParameters& layoutParameters,
-              const Size& layoutSize,
-              const Vector<LineRun>& lines,
-              Vector<Vector2>& glyphPositions );
+  void Align( const Size& layoutSize,
+              Vector<LineRun>& lines );
 
 private:
 
index 5668669..584d758 100644 (file)
@@ -38,15 +38,16 @@ namespace Text
  */
 struct LineRun
 {
-  GlyphIndex         glyphIndex;     ///< The initial glyph index.
-  Length             numberOfGlyphs; ///< The number of glyphs of the run.
-  CharacterRun       characterRun;   ///< The initial character and the number of characters.
-  float              width;          ///< The line's width.
-  float              ascender;       ///< The line's ascender.
-  float              descender;      ///< The line's descender.
-  float              extraLength;    ///< The length of the white spaces at the end of the line.
-  CharacterDirection direction : 1;  ///< Direction of the first character of the paragraph.
-  bool               ellipsis  : 1;  ///< Wheter ellipsis is added to the line.
+  GlyphIndex         glyphIndex;      ///< The initial glyph index.
+  Length             numberOfGlyphs;  ///< The number of glyphs of the run.
+  CharacterRun       characterRun;    ///< The initial character and the number of characters.
+  float              width;           ///< The line's width.
+  float              ascender;        ///< The line's ascender.
+  float              descender;       ///< The line's descender.
+  float              extraLength;     ///< The length of the white spaces at the end of the line.
+  float              alignmentOffset; ///< The horizontal alignment offset.
+  CharacterDirection direction : 1;   ///< Direction of the first character of the paragraph.
+  bool               ellipsis  : 1;   ///< Wheter ellipsis is added to the line.
 };
 
 } // namespace Text
index 2faca97..7dbe628 100644 (file)
@@ -35,112 +35,6 @@ LogicalModelPtr LogicalModel::New()
   return LogicalModelPtr( new LogicalModel() );
 }
 
-void LogicalModel::SetText( const Character* const text,
-                            Length numberOfCharacters )
-{
-  if( 0u == numberOfCharacters )
-  {
-    mText.Clear();
-  }
-  else
-  {
-    mText.Resize( numberOfCharacters );
-    memcpy( mText.Begin(), text, numberOfCharacters * sizeof( Character ) );
-  }
-}
-
-Length LogicalModel::GetNumberOfCharacters() const
-{
-  return mText.Count();
-}
-
-void LogicalModel::GetText( Character* text,
-                            CharacterIndex characterIndex,
-                            Length numberOfCharacters ) const
-{
-  memcpy( text, mText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
-}
-
-Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
-{
-  return mText[characterIndex];
-}
-
-void LogicalModel::ReplaceText( CharacterIndex characterIndex,
-                                Length numberOfCharactersToRemove,
-                                const Character* const text,
-                                Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetScripts( const ScriptRun* const scripts,
-                               Length numberOfRuns )
-{
-  if( 0u == numberOfRuns )
-  {
-    mScriptRuns.Clear();
-  }
-  else
-  {
-    mScriptRuns.Resize( numberOfRuns );
-    memcpy( mScriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
-  }
-}
-
-void LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
-                                          Length numberOfCharacters,
-                                          ScriptRunIndex& firstScriptRun,
-                                          Length& numberOfScriptRuns ) const
-{
-  // Initialize the number of scripts and the index to the first script.
-  firstScriptRun = 0u;
-  numberOfScriptRuns = 0;
-  bool firstScriptFound = false;
-
-  const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
-
-  // Traverse the scripts and count those scripts within the range of characters.
-  for( Vector<ScriptRun>::ConstIterator it = mScriptRuns.Begin(),
-         endIt = mScriptRuns.End();
-       it != endIt;
-       ++it )
-  {
-    const ScriptRun& script = *it;
-
-    if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) &&
-        ( lastCharacterIndex > script.characterRun.characterIndex ) )
-    {
-      firstScriptFound = true;
-      ++numberOfScriptRuns;
-    }
-    else if( lastCharacterIndex <= script.characterRun.characterIndex )
-    {
-      // nothing else to do.
-      break;
-    }
-
-    if( !firstScriptFound )
-    {
-      ++firstScriptRun;
-    }
-  }
-}
-
-void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
-                                  CharacterIndex characterIndex,
-                                  Length numberOfCharacters ) const
-{
-  ScriptRunIndex firstScriptRun = 0u;
-  Length numberOfScriptRuns = 0u;
-
-  GetNumberOfScriptRuns( characterIndex,
-                         numberOfCharacters,
-                         firstScriptRun,
-                         numberOfScriptRuns );
-
-  memcpy( scriptRuns, mScriptRuns.Begin() + firstScriptRun, numberOfScriptRuns * sizeof( ScriptRun ) );
-}
-
 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
 {
   // If this operation is too slow, consider a binary search.
@@ -159,265 +53,6 @@ Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
   return TextAbstraction::UNKNOWN;
 }
 
-void LogicalModel::ReplaceScripts( CharacterIndex characterIndex,
-                                   Length numberOfCharactersToRemove,
-                                   const ScriptRun* const scriptRuns,
-                                   Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetFonts( const FontRun* const fonts,
-                             Length numberOfRuns )
-{
-  if( 0u == numberOfRuns )
-  {
-    mFontRuns.Clear();
-  }
-  else
-  {
-    mFontRuns.Resize( numberOfRuns );
-    memcpy( mFontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
-  }
-}
-
-void LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
-                                        Length numberOfCharacters,
-                                        FontRunIndex& firstFontRun,
-                                        Length& numberOfFontRuns ) const
-{
-  // Initialize the number of fonts and the index to the first font.
-  firstFontRun = 0u;
-  numberOfFontRuns = 0;
-  bool firstFontFound = false;
-
-  const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
-
-  // Traverse the fonts and count those fonts within the range of characters.
-  for( Vector<FontRun>::ConstIterator it = mFontRuns.Begin(),
-         endIt = mFontRuns.End();
-       it != endIt;
-       ++it )
-  {
-    const FontRun& font = *it;
-
-    if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
-        ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
-    {
-      firstFontFound = true;
-      ++numberOfFontRuns;
-    }
-    else if( lastCharacterIndex <= font.characterRun.characterIndex )
-    {
-      // nothing else to do.
-      break;
-    }
-
-    if( !firstFontFound )
-    {
-      ++firstFontRun;
-    }
-  }
-}
-
-void LogicalModel::GetFontRuns( FontRun* fontRuns,
-                                CharacterIndex characterIndex,
-                                Length numberOfCharacters ) const
-{
-  FontRunIndex firstFontRun = 0u;
-  Length numberOfFontRuns = 0u;
-
-  GetNumberOfFontRuns( characterIndex,
-                       numberOfCharacters,
-                       firstFontRun,
-                       numberOfFontRuns );
-
-  memcpy( fontRuns, mFontRuns.Begin() + firstFontRun, numberOfFontRuns * sizeof( FontRun ) );
-}
-
-FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
-{
-  for( Length index = 0u, length = mFontRuns.Count(); index < length; ++index )
-  {
-    const FontRun* const fontRun = mFontRuns.Begin() + index;
-
-    if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
-        ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
-    {
-      return fontRun->fontId;
-    }
-  }
-
-  return 0u;
-}
-
-void LogicalModel::ReplaceFonts( CharacterIndex characterIndex,
-                                 Length numberOfCharactersToRemove,
-                                 const FontRun* const fontRuns,
-                                 Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
-                                     Length length )
-{
-  if( 0u == length )
-  {
-    mLineBreakInfo.Clear();
-  }
-  else
-  {
-    mLineBreakInfo.Resize( length );
-    memcpy( mLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
-  }
-}
-
-void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
-                                     CharacterIndex characterIndex,
-                                     Length numberOfItems ) const
-{
-  memcpy( lineBreakInfo, mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
-}
-
-LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
-{
-  return *( mLineBreakInfo.Begin() + characterIndex );
-}
-
-void LogicalModel::ReplaceLineBreakInfo( CharacterIndex characterIndex,
-                                         Length numberOfItemsToRemove,
-                                         const LineBreakInfo* const lineBreakInfo,
-                                         Length numberOfItemsToInsert )
-{
-}
-
-void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
-                                     Length length )
-{
-  if( 0u == length )
-  {
-    mWordBreakInfo.Clear();
-  }
-  else
-  {
-    mWordBreakInfo.Resize( length );
-    memcpy( mWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
-  }
-}
-
-void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
-                                     CharacterIndex characterIndex,
-                                     Length numberOfItems ) const
-{
-  memcpy( wordBreakInfo, mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
-}
-
-WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
-{
-  return *( mWordBreakInfo.Begin() + characterIndex );
-}
-
-void LogicalModel::ReplaceWordBreakInfo( CharacterIndex characterIndex,
-                                         Length numberOfItemsToRemove,
-                                         const WordBreakInfo* const wordBreakInfo,
-                                         Length numberOfItemsToInsert )
-{
-}
-
-void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
-                                         Length numberOfRuns )
-{
-  if( 0u == numberOfRuns )
-  {
-    mBidirectionalParagraphInfo.Clear();
-  }
-  else
-  {
-    mBidirectionalParagraphInfo.Resize( numberOfRuns );
-    memcpy( mBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
-  }
-}
-
-void LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
-                                                     Length numberOfCharacters,
-                                                     BidirectionalRunIndex& firstBidirectionalRun,
-                                                     Length& numberOfFontRuns  ) const
-{
-  // Initialize the number of bidi paragraphs and the index to the first paragraph.
-  firstBidirectionalRun = 0u;
-  numberOfFontRuns = 0;
-  bool firstParagraphFound = false;
-
-  // Traverse the bidirectional paragraph info and count those bidi paragraphs within the range of characters.
-  for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = mBidirectionalParagraphInfo.Begin(),
-         endIt = mBidirectionalParagraphInfo.End();
-       it != endIt;
-       ++it )
-  {
-    const BidirectionalParagraphInfoRun& bidi = *it;
-
-    if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) &&
-        ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) )
-    {
-      firstParagraphFound = true;
-      ++numberOfFontRuns;
-    }
-
-    if( !firstParagraphFound )
-    {
-      ++firstBidirectionalRun;
-    }
-  }
-}
-
-void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
-                                         CharacterIndex characterIndex,
-                                         Length numberOfCharacters ) const
-{
-  BidirectionalRunIndex firstBidirectionalRun = 0u;
-  Length numberOfFontRuns = 0u;
-
-  GetNumberOfBidirectionalInfoRuns( characterIndex,
-                                    numberOfCharacters,
-                                    firstBidirectionalRun,
-                                    numberOfFontRuns );
-
-  memcpy( bidirectionalInfo, mBidirectionalParagraphInfo.Begin() + firstBidirectionalRun, numberOfFontRuns * sizeof( BidirectionalParagraphInfoRun ) );
-}
-
-void ReplaceBidirectionalInfo( CharacterIndex characterIndex,
-                               Length numberOfCharactersToRemove,
-                               const BidirectionalParagraphInfoRun* const bidirectionalInfo,
-                               Length numberOfCharactersToInsert )
-{
-}
-
-void LogicalModel::SetCharacterDirections( const CharacterDirection* const directions,
-                                           Length numberOfCharacters )
-{
-  if( 0u == numberOfCharacters )
-  {
-    mCharacterDirections.Clear();
-  }
-  else
-  {
-    mCharacterDirections.Resize( numberOfCharacters );
-    memcpy( mCharacterDirections.Begin(), directions, numberOfCharacters * sizeof( CharacterDirection ) );
-  }
-}
-
-void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
-                                           CharacterIndex characterIndex,
-                                           Length numberOfCharacters ) const
-{
-  if( 0u == mCharacterDirections.Count() )
-  {
-    // Nothing to retrieve if the model has no right to left characters.
-    return;
-  }
-
-  memcpy( directions, mCharacterDirections.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterDirection ) );
-}
-
 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
 {
   if( characterIndex >= mCharacterDirections.Count() )
@@ -597,25 +232,6 @@ void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const
   }
 }
 
-void LogicalModel::ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
-                                              Length numberOfCharactersToRemove,
-                                              const BidirectionalLineInfoRun* const bidirectionalInfo,
-                                              Length numberOfCharactersToInsert )
-{
-}
-
-CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
-{
-  if( 0u == mLogicalToVisualMap.Count() )
-  {
-    // If there is no logical to visual info is because the whole text is left to right.
-    // Return the identity.
-    return logicalCharacterIndex;
-  }
-
-  return *( mLogicalToVisualMap.Begin() + logicalCharacterIndex );
-}
-
 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
 {
   if( 0u == mVisualToLogicalMap.Count() )
@@ -628,20 +244,6 @@ CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualChar
   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
 }
 
-void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharacters ) const
-{
-  memcpy( logicalToVisualMap, mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
-}
-
-void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharacters ) const
-{
-  memcpy( visualToLogicalMap, mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
-}
-
 LogicalModel::~LogicalModel()
 {
 }
index 73d9230..269247f 100644 (file)
@@ -62,110 +62,9 @@ public:
    */
   static LogicalModelPtr New();
 
-  // Text interface.
-
-  /**
-   * @brief Replaces any text previously set.
-   *
-   * @note If the number of characters is zero the text buffer is cleared.
-   *
-   * @param[in] text An array of UTF-32 characters.
-   * @param[in] numberOfCharacters The length of the array.
-   */
-  void SetText( const Character* const text,
-                Length numberOfCharacters );
-
-  /**
-   * @brief Retrieves the number of characters of the text.
-   *
-   * @return The number of characters.
-   */
-  Length GetNumberOfCharacters() const;
-
-  /**
-   * @brief Retrieves characters from the text in the given buffer.
-   *
-   * @pre The size of the @p text buffer needs to be big enough to copy the @p numberOfCharacters.
-   * @param[out] text Pointer to a buffer where the text is copied.
-   * @param[in] characterIndex The index to the first character to copy.
-   * @param[in] numberOfCharacters The number of characters to be copied.
-   */
-  void GetText( Character* text,
-                CharacterIndex characterIndex,
-                Length numberOfCharacters ) const;
-
-  /**
-   * @brief Retrieves a character.
-   *
-   * @param[in] characterIndex Index to a character.
-   *
-   * @return A character.
-   */
-  Character GetCharacter( CharacterIndex characterIndex ) const;
-
-  /**
-   * @brief Replaces characters from the text.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Where to replace the text.
-   * @param[in] numberOfCharactersToRemove The number of characters to be removed.
-   * @param[in] text Pointer to a buffer with the text encoded in utf32.
-   * @param[in] numberOfCharactersToInsert The number of characters in the buffer.
-   */
-  void ReplaceText( CharacterIndex characterIndex,
-                    Length numberOfCharactersToRemove,
-                    const Character* const text,
-                    Length numberOfCharactersToInsert );
-
   // Language support interface.
 
   /**
-   * @brief Sets the script runs.
-   *
-   * Replaces any scripts previously set.
-   *
-   * A run is a group of consecutive characters. A script run contains the script for a run.
-   *
-   * @note If the number of runs is zero the script buffer is cleared.
-   *
-   * @param[in] scripts Pointer to a buffer with all the script runs.
-   * @param[in] numberOfRuns The number of script runs.
-   */
-  void SetScripts( const ScriptRun* const scripts,
-                   Length numberOfRuns );
-
-  /**
-   * @brief Retrieves the number of script runs and the index to the first one for the given range of characters.
-   *
-   * A run is a group of consecutive characters. A script run contains the script for a run.
-   *
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   * @param[out] firstScriptRun Index to the script run containing the character index.
-   * @param[out] numberOfScriptRuns The number of script runs.
-   */
-  void GetNumberOfScriptRuns( CharacterIndex characterIndex,
-                              Length numberOfCharacters,
-                              ScriptRunIndex& firstScriptRun,
-                              Length& numberOfScriptRuns ) const;
-
-  /**
-   * @brief Retrieves the script runs for the given range of characters.
-   *
-   * The @p scriptRuns buffer needs to be big enough to copy the number of script runs.
-   * Call GetNumberOfScriptRuns() to retrieve the number of script runs.
-   *
-   * @param[out] scriptRuns Pointer to a buffer where the script runs are copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetScriptRuns( ScriptRun* scriptRuns,
-                      CharacterIndex characterIndex,
-                      Length numberOfCharacters ) const;
-
-  /**
    * @brief Retrieves the script for the given character index.
    *
    * @param[in] characterIndex Index to the character.
@@ -174,322 +73,9 @@ public:
    */
   Script GetScript( CharacterIndex characterIndex ) const;
 
-  /**
-   * @brief Replaces script runs for the given range of characters.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Index of the first character where to replace the scripts.
-   * @param[in] numberOfCharactersToRemove The number of characters to be the script removed.
-   * @param[in] scriptRuns Pointer to a buffer with the script runs.
-   * @param[in] numberOfCharactersToInsert The number of characters to be the script inserted.
-   */
-  void ReplaceScripts( CharacterIndex characterIndex,
-                       Length numberOfCharactersToRemove,
-                       const ScriptRun* const scriptRuns,
-                       Length numberOfCharactersToInsert );
-
-  /**
-   * @brief Sets the font runs.
-   *
-   * Replaces any fonts previously set.
-   *
-   * A run is a group of consecutive characters. A font run contains the font id for a run.
-   *
-   * @note If the number of runs is zero the font buffer is cleared.
-   *
-   * @param[in] fonts Pointer to a buffer with all the font runs.
-   * @param[in] numberOfRuns The number of font runs.
-   */
-  void SetFonts( const FontRun* const fonts,
-                 Length numberOfRuns );
-
-  /**
-   * @brief Retrieves the number of font runs and the index of the first one for the given range of characters.
-   *
-   * A run is a group of consecutive characters. A font run contains the font id for a run.
-   *
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   * @param[out] firstFontRun Index to the font run containing the character index.
-   * @param[out] numberOfFontRuns The number of font runs.
-   */
-  void GetNumberOfFontRuns( CharacterIndex characterIndex,
-                            Length numberOfCharacters,
-                            FontRunIndex& firstFontRun,
-                            Length& numberOfFontRuns ) const;
-
-  /**
-   * @brief Retrieves the font runs for the given range of characters.
-   *
-   * The @p fontRuns buffer needs to be big enough to copy the number of font runs.
-   * Call GetNumberOfFontRuns() to retrieve the number of font runs.
-   *
-   * @param[out] fontRuns Pointer to a buffer where the font runs are copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetFontRuns( FontRun* fontRuns,
-                    CharacterIndex characterIndex,
-                    Length numberOfCharacters ) const;
-
-  /**
-   * @brief Retrieves the font id for the given character index.
-   *
-   * @param[in] characterIndex Index to the first character.
-   *
-   * @return The font id.
-   */
-  FontId GetFont( CharacterIndex characterIndex ) const;
-
-  /**
-   * @brief Replaces font runs for the given range of characters.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Index of the first character where to replace the fonts.
-   * @param[in] numberOfCharactersToRemove The number of characters to be the font removed.
-   * @param[in] fontRuns Pointer to a buffer with the font runs.
-   * @param[in] numberOfCharactersToInsert The number of characters to be the font inserted.
-   */
-  void ReplaceFonts( CharacterIndex characterIndex,
-                     Length numberOfCharactersToRemove,
-                     const FontRun* const fontRuns,
-                     Length numberOfCharactersToInsert );
-
-  // Break info interface.
-
-  /**
-   * @brief Sets the line break info.
-   *
-   * See GetLineBreakInfo() to get how the line break info is encoded.
-   *
-   * Replaces any line break info previously set.
-   *
-   * @note If the @length is zero the break info buffer is cleared.
-   *
-   * @param[in] lineBreakInfo Pointer to a buffer with the line break info.
-   * @param[in] length The size of the buffer.
-   */
-  void SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
-                         Length length );
-
-  /**
-   * @brief Retrieves the line break info in the given buffer.
-   *
-   * The size of the @p lineBreakInfo buffer needs to be big enough to copy the @p numberOfItems.
-   *
-   * Possible values for LineBreakInfo are:
-   *
-   *  - 0 is a LINE_MUST_BREAK.  Text must be broken into a new line.
-   *  - 1 is a LINE_ALLOW_BREAK. Is possible to break the text into a new line.
-   *  - 2 is a LINE_NO_BREAK.    Text can't be broken into a new line.
-   *
-     @verbatim
-     i.e. Hello big\nworld produces:
-          2222212220 22220
-     @endverbatim
-   *
-   * @param[out] lineBreakInfo Pointer to a buffer where the line break info is copied.
-   * @param[in] characterIndex Index to the first line break info item.
-   * @param[in] numberOfItems The number of items to be copied.
-   */
-  void GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
-                         CharacterIndex characterIndex,
-                         Length numberOfItems ) const;
-
-  /**
-   * @brief Retrieves the line break info for the given item index.
-   *
-   * @param[in] characterIndex Index to the line break info item.
-   */
-  LineBreakInfo GetLineBreakInfo( CharacterIndex characterIndex ) const;
-
-  /**
-   * @brief Replaces line break info.
-   *
-   * See GetLineBreakInfo() to get how the line break info is encoded.
-   *
-   * If the @p numberOfItemsToRemove is zero, this operation is like an insert.
-   * If the @p numberOfItemsToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Where to replace the line break info.
-   * @param[in] numberOfItemsToRemove The number of items to be removed.
-   * @param[in] lineBreakInfo Pointer to a buffer with the line break info.
-   * @param[in] numberOfItemsToInsert The number of items in the buffer.
-   */
-  void ReplaceLineBreakInfo( CharacterIndex characterIndex,
-                             Length numberOfItemsToRemove,
-                             const LineBreakInfo* const lineBreakInfo,
-                             Length numberOfItemsToInsert );
-
-  /**
-   * @brief Sets the word break info.
-   *
-   * See GetWordBreakInfo() to get how the word break info is encoded.
-   *
-   * Replaces any word break info previously set.
-   *
-   * @note If the @length is zero the break info buffer is cleared.
-   *
-   * @param[in] wordBreakInfo Pointer to a buffer with the word break info.
-   * @param[in] length The size of the buffer.
-   */
-  void SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
-                         Length length );
-
-  /**
-   * @brief Retrieves the word break info in the given buffer.
-   *
-   * The size of the @p wordBreakInfo buffer needs to be big enough to copy the @p numberOfItems.
-   *
-   * The size of the buffer has to be big enough to store the whole word break info per character.
-   * Call GetNumberOfCharacters() to get the number of characters.
-   *
-   * Possible values for WordBreakInfo are:
-   *
-   * - 0 is a WORD_BREAK.    Text can be broken into a new word.
-   * - 1 is a WORD_NO_BREAK. Text can't be broken into a new word.
-   *
-     @verbatim
-     i.e. Hello big\nworld produces:
-          1111001100 11110
-     @endverbatim
-   *
-   * @param[out] wordBreakInfo Pointer to a buffer where the word break info is copied.
-   * @param[in] characterIndex Index to the first word break info item.
-   * @param[in] numberOfItems The number of items to be copied.
-   */
-  void GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
-                         CharacterIndex characterIndex,
-                         Length numberOfItems ) const;
-
-  /**
-   * @brief Retrieves the word break info for the given item index.
-   *
-   * @param[in] characterIndex Index to the word break info item.
-   */
-  WordBreakInfo GetWordBreakInfo( CharacterIndex characterIndex ) const;
-
-  /**
-   * @brief Replaces word break info.
-   *
-   * See GetWordBreakInfo() to get how the word break info is encoded.
-   *
-   * If the @p numberOfItemsToRemove is zero, this operation is like an insert.
-   * If the @p numberOfItemsToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Where to replace the word break info.
-   * @param[in] numberOfItemsToRemove The number of items to be removed.
-   * @param[in] wordBreakInfo Pointer to a buffer with the word break info.
-   * @param[in] numberOfItemsToInsert The number of items in the buffer.
-   */
-  void ReplaceWordBreakInfo( CharacterIndex characterIndex,
-                             Length numberOfItemsToRemove,
-                             const WordBreakInfo* const wordBreakInfo,
-                             Length numberOfItemsToInsert );
-
   // Bidirectional support interface.
 
   /**
-   * @brief Sets the bidirectional info runs.
-   *
-   * Replaces any bidirectional info previously set.
-   *
-   * Each bidirectional info run stores bidirectional info for a whole 'paragraph' of text which contains right to left scripts.
-
-   * In terms of the bidirectional algorithm, a 'paragraph' is understood as a run of characters between Paragraph Separators or appropriate Newline Functions.
-   * A 'paragraph' may also be determined by higher-level protocols like a mark-up tag.
-   *
-   * @note If the number of runs is zero the bidirectional info buffer is cleared.
-   *
-   * @param[in] bidirectionalInfo Pointer to a buffer with all the bidirectional info runs.
-   * @param[in] numberOfRuns The number of bidirectional info runs.
-   */
-  void SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
-                             Length numberOfRuns );
-
-  /**
-   * @brief Retrieves the number of bidirectional info runs and the index to the first one for the given range of characters.
-   *
-   * It may be zero if there is no right to left scripts.
-   *
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   *
-   * @return The number of bidirectional info runs.
-   */
-  void GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
-                                         Length numberOfCharacters,
-                                         BidirectionalRunIndex& firstBidirectionalRun,
-                                         Length& numberOfFontRuns ) const;
-
-  /**
-   * @brief Retrieves the bidirectional paragraph info runs for the given range of characters.
-   *
-   * The @p bidirectionalInfo buffer needs to be big enough to copy the number of bidirectional
-   * paragraph info runs.
-   * Call GetNumberOfBidirectionalInfoRuns() to retrieve the number of bidirectional runs.
-   *
-   * @param[out] bidirectionalInfo Pointer to a buffer where the bidirectional info runs are copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
-                             CharacterIndex characterIndex,
-                             Length numberOfCharacters ) const;
-
-  /**
-   * @brief Replaces bidirectional info runs for the given range of characters.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Index of the first character where to replace the bidirectional info.
-   * @param[in] numberOfCharactersToRemove The number of characters to be the bidirectional info removed.
-   * @param[in] bidirectionalInfo Pointer to a buffer with the bidirectional info runs.
-   * @param[in] numberOfCharactersToInsert The number of characters to be the bidirectional info inserted.
-   */
-  void ReplaceBidirectionalInfo( CharacterIndex characterIndex,
-                                 Length numberOfCharactersToRemove,
-                                 const BidirectionalParagraphInfoRun* const bidirectionalInfo,
-                                 Length numberOfCharactersToInsert );
-
-  /**
-   * @brief Replaces the direction of the characters.
-   *
-   * @note If the number of characters is zero the directions buffer is cleared.
-   *
-   * @param[in] directions The directions of the characters.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void SetCharacterDirections( const CharacterDirection* const directions,
-                               Length numberOfCharacters );
-
-  /**
-   * @brief Retrieves the direction of the characters.
-   *
-   * It sets @e true for right to left characters and @e false for left to right.
-   * For neutral characters it check's the next and previous character's directions:
-   * - If they are equals set that direction. If they are not, sets the paragraph's direction.
-   * - If there is no next, sets the paragraph's direction.
-   *
-   * See SetBidirectionalInfo() to get an explanation of the 'paragraph' meaning in the bidirectional algorithm.
-   *
-   * @pre the @p directions vector should be initialized to @e false (left to right) as this method is not going
-   *      to update it if there is no right to left characters.
-   *
-   * @param[out] directions Whether the characters are right to left or left to right.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetCharacterDirections( CharacterDirection* directions,
-                               CharacterIndex characterIndex,
-                               Length numberOfCharacters ) const;
-
-  /**
    * @brief Retrieves the direction of a characters.
    *
    * See GetCharacterDirections().
@@ -516,31 +102,6 @@ public:
                               Length numberOfRuns );
 
   /**
-   * @brief Replaces the visual to logical and logical to visual map tables for the given range of characters.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] characterIndex Index of the first character where to replace the map tables.
-   * @param[in] numberOfCharactersToRemove The number of characters to be removed.
-   * @param[in] bidirectionalInfo Pointer to a buffer with the bidirectional info runs.
-   * @param[in] numberOfCharactersToInsert The number of characters to be inserted.
-   */
-  void ReplaceVisualToLogicalMap( CharacterIndex characterIndex,
-                                  Length numberOfCharactersToRemove,
-                                  const BidirectionalLineInfoRun* const bidirectionalInfo,
-                                  Length numberOfCharactersToInsert );
-
-  /**
-   * @brief Retrieves the visual character index for the given logical character index.
-   *
-   * @param[in] logicalCharacterIndex The logical character index.
-   *
-   * @return The visual character index.
-   */
-  CharacterIndex GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const;
-
-  /**
    * @brief Retrieves the logical character index for the given visual character index.
    *
    * @param[in] visualCharacterIndex The visual character index.
@@ -549,32 +110,6 @@ public:
    */
   CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
 
-  /**
-   * @brief Retrieves the whole or part of the logical to visual conversion map.
-   *
-   * The size of the buffer needs to be big enough to copy the @p numberOfCharacters.
-   *
-   * @param[out] logicalToVisualMap Pointer to a buffer where the conversion map is copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
-                              CharacterIndex characterIndex,
-                              Length numberOfCharacters ) const;
-
-  /**
-   * @brief Retrieves the whole or part of the visual to logical conversion map.
-   *
-   * The size of the buffer needs to be big enough to copy the @p numberOfCharacters.
-   *
-   * @param[out] visualToLogicalMap Pointer to a buffer where the conversion map is copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
-                              CharacterIndex characterIndex,
-                              Length numberOfCharacters ) const;
-
 protected:
 
   /**
index 47db1e2..3fa8f6f 100644 (file)
@@ -126,24 +126,6 @@ Script GetScript( Length index,
   return script;
 }
 
-/**
- * @brief Whether the character is valid for all scripts. i.e. the white space.
- *
- * @param[in] character The character.
- *
- * @return @e true if the character is valid for all scripts.
- */
-bool IsValidForAllScripts( Character character )
-{
-  return ( TextAbstraction::IsWhiteSpace( character )         ||
-           TextAbstraction::IsZeroWidthNonJoiner( character ) ||
-           TextAbstraction::IsZeroWidthJoiner( character )    ||
-           TextAbstraction::IsZeroWidthSpace( character )     ||
-           TextAbstraction::IsLeftToRightMark( character )    ||
-           TextAbstraction::IsRightToLeftMark( character )    ||
-           TextAbstraction::IsThinSpace( character ) );
-}
-
 bool ValidateFontsPerScript::FindValidFont( FontId fontId ) const
 {
   for( Vector<FontId>::ConstIterator it = mValidFonts.Begin(),
@@ -262,7 +244,7 @@ void MultilanguageSupport::SetScripts( const Vector<Character>& text,
     // Skip those characters valid for many scripts like white spaces or '\n'.
     bool endOfText = index == numberOfCharacters;
     while( !endOfText &&
-           IsValidForAllScripts( character ) )
+           TextAbstraction::IsCommonScript( character ) )
     {
       // Count all these characters to be added into a script.
       ++numberOfAllScriptCharacters;
@@ -350,34 +332,29 @@ void MultilanguageSupport::SetScripts( const Vector<Character>& text,
 
   // Add remaining characters into the last script.
   currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
-  if( 0u != currentScriptRun.characterRun.numberOfCharacters )
-  {
-    if( TextAbstraction::UNKNOWN == currentScriptRun.script )
-    {
-      // There are only white spaces in the last script. Set the latin script.
-      currentScriptRun.script = TextAbstraction::LATIN;
-    }
 
-    // Store the last run.
-    scripts.PushBack( currentScriptRun );
+  DALI_ASSERT_DEBUG( ( 0u != currentScriptRun.characterRun.numberOfCharacters ) && "MultilanguageSupport::SetScripts() Trying to insert a script run with zero characters." );
+
+  if( TextAbstraction::UNKNOWN == currentScriptRun.script )
+  {
+    // There are only white spaces in the last script. Set the latin script.
+    currentScriptRun.script = TextAbstraction::LATIN;
   }
-}
 
-void MultilanguageSupport::ReplaceScripts( LogicalModel& model,
-                                           CharacterIndex characterIndex,
-                                           Length numberOfCharactersToRemove,
-                                           Length numberOfCharactersToInsert )
-{
+  // Store the last run.
+  scripts.PushBack( currentScriptRun );
 }
 
 void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
                                           const Vector<ScriptRun>& scripts,
                                           Vector<FontRun>& fonts )
 {
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->MultilanguageSupport::ValidateFonts\n" );
   const Length numberOfCharacters = text.Count();
 
   if( 0u == numberOfCharacters )
   {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--MultilanguageSupport::ValidateFonts\n" );
     // Nothing to do if there are no characters.
     return;
   }
@@ -427,6 +404,20 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
                                scriptRunIt,
                                scriptRunEndIt );
 
+#ifdef DEBUG_ENABLED
+    {
+      Dali::TextAbstraction::FontDescription description;
+      fontClient.GetDescription( fontId, description );
+
+      DALI_LOG_INFO( gLogFilter,
+                     Debug::Verbose,
+                     "  Initial font set\n  Character : %x, Script : %s, Font : %s \n",
+                     character,
+                     Dali::TextAbstraction::ScriptName[script],
+                     description.path.c_str() );
+    }
+#endif
+
     if( TextAbstraction::UNKNOWN == script )
     {
       DALI_LOG_WARNING( "MultilanguageSupport::ValidateFonts. Unknown script!" );
@@ -436,6 +427,11 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
     // Whether the font being validated is a default one not set by the user.
     const bool isDefault = ( 0u == fontId );
 
+    DALI_LOG_INFO( gLogFilter,
+                   Debug::Verbose,
+                   "  Is a default font : %s\n",
+                   ( isDefault ? "true" : "false" ) );
+
     // The default font point size.
     PointSize26Dot6 pointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
 
@@ -488,6 +484,26 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
             else
             {
               // Add the font to the valid font cache.
+
+              //   At this point the validated font supports the given character. However, characters
+              // common for all scripts, like white spaces or new paragraph characters, need to be
+              // processed differently.
+              //
+              //   i.e. A white space can have assigned a DEVANAGARI script but the font assigned may not
+              // support none of the DEVANAGARI glyphs. This font can't be added to the cache as a valid
+              // font for the DEVANAGARI script but the COMMON one.
+              if( TextAbstraction::IsCommonScript( character ) )
+              {
+                validateFontsPerScript = *( validFontsPerScriptCacheBuffer + TextAbstraction::COMMON );
+
+                if( NULL == validateFontsPerScript )
+                {
+                  validateFontsPerScript = new ValidateFontsPerScript();
+
+                  *( validFontsPerScriptCacheBuffer + TextAbstraction::COMMON ) = validateFontsPerScript;
+                }
+              }
+
               validateFontsPerScript->mValidFonts.PushBack( fontId );
             }
           }
@@ -520,16 +536,24 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
           fontId = fontClient.FindDefaultFont( UTF32_A, pointSize );
         }
 
-#ifdef DEBUG_ENABLED
-        Dali::TextAbstraction::FontDescription description;
-        fontClient.GetDescription( fontId, description );
-        DALI_LOG_INFO( gLogFilter, Debug::Concise, "Script: %s; Selected font: %s\n", Dali::TextAbstraction::ScriptName[script], description.path.c_str() );
-#endif
         // Cache the font.
         *( defaultFontPerScriptCacheBuffer + script ) = fontId;
       }
     }
 
+#ifdef DEBUG_ENABLED
+    {
+      Dali::TextAbstraction::FontDescription description;
+      fontClient.GetDescription( fontId, description );
+      DALI_LOG_INFO( gLogFilter,
+                     Debug::Verbose,
+                     "  Validated font set\n  Character : %x, Script : %s, Font : %s \n",
+                     character,
+                     Dali::TextAbstraction::ScriptName[script],
+                     description.path.c_str() );
+    }
+#endif
+
     // The font is now validated.
 
     if( ( fontId != currentFontRun.fontId ) ||
@@ -559,13 +583,7 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
     // Store the last run.
     fonts.PushBack( currentFontRun );
   }
-}
-
-void MultilanguageSupport::ValidateFonts( LogicalModel& model,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharactersToRemove,
-                                          Length numberOfCharactersToInsert )
-{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--MultilanguageSupport::ValidateFonts\n" );
 }
 
 } // namespace Internal
index 0f7e177..ee91aae 100644 (file)
@@ -98,27 +98,12 @@ public:
                    Vector<ScriptRun>& scripts );
 
   /**
-   * @copydoc Dali::MultilanguageSupport::ReplaceScripts()
-   */
-  void ReplaceScripts( LogicalModel& model,
-                       CharacterIndex characterIndex,
-                       Length numberOfCharactersToRemove,
-                       Length numberOfCharactersToInsert );
-
-  /**
    * @copydoc Dali::MultilanguageSupport::ValidateFonts( const Vector<Character>& text, const Vector<ScriptRun>& scripts, Vector<FontRun>& fonts )
    */
   void ValidateFonts( const Vector<Character>& text,
                       const Vector<ScriptRun>& scripts,
                       Vector<FontRun>& fonts );
 
-  /**
-   * @copydoc Dali::MultilanguageSupport::ValidateFonts( LogicalModel& model, CharacterIndex characterIndex, Length numberOfCharactersToRemove, Length numberOfCharactersToInsert )
-   */
-  void ValidateFonts( LogicalModel& model,
-                      CharacterIndex characterIndex,
-                      Length numberOfCharactersToRemove,
-                      Length numberOfCharactersToInsert );
 private:
   Vector<FontId>                  mDefaultFontPerScriptCache; ///< Caches the default font for a script.
   Vector<ValidateFontsPerScript*> mValidFontsPerScriptCache;  ///< Caches valid fonts for a script.
index 4416dba..8c28dd5 100644 (file)
@@ -57,17 +57,6 @@ void MultilanguageSupport::SetScripts( const Vector<Character>& text,
                                          scripts );
 }
 
-void MultilanguageSupport::ReplaceScripts( LogicalModel& model,
-                                           CharacterIndex characterIndex,
-                                           Length numberOfCharactersToRemove,
-                                           Length numberOfCharactersToInsert )
-{
-  GetImplementation( *this ).ReplaceScripts( model,
-                                             characterIndex,
-                                             numberOfCharactersToRemove,
-                                             numberOfCharactersToInsert );
-}
-
 void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
                                           const Vector<ScriptRun>& scripts,
                                           Vector<FontRun>& fonts )
@@ -77,17 +66,6 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
                                             fonts );
 }
 
-void MultilanguageSupport::ValidateFonts( LogicalModel& model,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharactersToRemove,
-                                          Length numberOfCharactersToInsert )
-{
-  GetImplementation( *this ).ValidateFonts( model,
-                                            characterIndex,
-                                            numberOfCharactersToRemove,
-                                            numberOfCharactersToInsert );
-}
-
 } // namespace Text
 
 } // namespace Toolkit
index b70f672..a22676c 100644 (file)
@@ -99,24 +99,6 @@ public:
                    Vector<ScriptRun>& scripts );
 
   /**
-   * Replaces the scrips of the given range of characters.
-   *
-   * @pre The @p model needs to have a text set.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in,out] model The text's logical model.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
-   * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
-   */
-  void ReplaceScripts( LogicalModel& model,
-                       CharacterIndex characterIndex,
-                       Length numberOfCharactersToRemove,
-                       Length numberOfCharactersToInsert );
-
-  /**
    * @brief Validates the character's font of the whole text.
    *
    * It may update fonts set by application developers.
@@ -136,28 +118,6 @@ public:
   void ValidateFonts( const Vector<Character>& text,
                       const Vector<ScriptRun>& scripts,
                       Vector<FontRun>& fonts );
-
-  /**
-   * Validates the character's font of the given range of characters.
-   *
-   * It may update fonts set by the mark-up processor.
-   * It sets default fonts based on the script to those characters without a font set.
-   *
-   * @pre The @p model needs to have a text set.
-   * @pre The @p model needs to have the scripts set.
-   *
-   * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
-   * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
-   *
-   * @param[in,out] model The text's logical model.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
-   * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
-   */
-  void ValidateFonts( LogicalModel& model,
-                      CharacterIndex characterIndex,
-                      Length numberOfCharactersToRemove,
-                      Length numberOfCharactersToInsert );
 };
 
 } // namespace Text
index cb90d03..fea111d 100644 (file)
@@ -97,6 +97,18 @@ AtlasGlyphManager::AtlasGlyphManager()
 
 AtlasGlyphManager::~AtlasGlyphManager()
 {
+  // Clear up any remaining references
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
+  {
+    for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+          glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
+          ++glyphRecordEntryIt )
+    {
+      mAtlasManager.Remove( glyphRecordEntryIt->mImageId );
+    }
+  }
 }
 
 AtlasGlyphManagerPtr AtlasGlyphManager::New()
@@ -105,24 +117,47 @@ AtlasGlyphManagerPtr AtlasGlyphManager::New()
   return internal;
 }
 
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+                             const Text::GlyphInfo& glyph,
                              const BufferImage& bitmap,
                              Dali::Toolkit::AtlasManager::AtlasSlot& slot )
 {
-  GlyphRecord record;
-  record.mFontId = glyph.fontId;
-  record.mIndex = glyph.index;
-
   mAtlasManager.Add( bitmap, slot );
+
+  GlyphRecordEntry record;
+  record.mIndex = glyph.index;
   record.mImageId = slot.mImageId;
-  mGlyphRecords.PushBack( record );
+  record.mCount = 1;
+
+  // Have glyph records been created for this fontId ?
+  bool foundGlyph = false;
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end(); ++fontGlyphRecordIt )
+  {
+    if ( fontGlyphRecordIt->mFontId == fontId )
+    {
+      fontGlyphRecordIt->mGlyphRecords.PushBack( record );
+      foundGlyph = true;
+      break;
+    }
+  }
+
+  if ( !foundGlyph )
+  {
+    // We need to add a new font entry
+    FontGlyphRecord fontGlyphRecord;
+    fontGlyphRecord.mFontId = fontId;
+    fontGlyphRecord.mGlyphRecords.PushBack( record );
+    mFontGlyphRecords.push_back( fontGlyphRecord );
+  }
 }
 
 void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
                                           const Vector2& position,
                                           Toolkit::AtlasManager::Mesh2D& mesh )
 {
-  mAtlasManager.GenerateMeshData( imageId, position, mesh );
+  // Generate mesh data and tell Atlas Manager not to handle reference counting ( we'll do it )
+  mAtlasManager.GenerateMeshData( imageId, position, mesh, false );
 }
 
 void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
@@ -131,20 +166,31 @@ void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
   mAtlasManager.StitchMesh( first, second );
 }
 
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
                                 uint32_t index,
                                 Dali::Toolkit::AtlasManager::AtlasSlot& slot )
 {
-  for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
   {
-    if ( fontId == mGlyphRecords[ i ].mFontId && index == mGlyphRecords[ i ].mIndex )
+    if ( fontGlyphRecordIt->mFontId == fontId )
     {
-      slot.mImageId = mGlyphRecords[ i ].mImageId;
-      slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
-      return;
+      for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+            glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+            ++glyphRecordIt )
+      {
+        if ( glyphRecordIt->mIndex == index )
+        {
+          slot.mImageId = glyphRecordIt->mImageId;
+          slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
+          return true;
+        }
+      }
     }
   }
   slot.mImageId = 0;
+  return false;
 }
 
 Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
@@ -163,26 +209,45 @@ void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32
   mAtlasManager.SetNewAtlasSize( size );
 }
 
-void AtlasGlyphManager::Remove( uint32_t imageId )
+Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
+{
+  return mAtlasManager.GetPixelFormat( atlasId );
+}
+
+const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
+{
+  mMetrics.mGlyphCount = mFontGlyphRecords.size();
+  mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
+  return mMetrics;
+}
+
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
 {
-  if ( mAtlasManager.Remove( imageId ) )
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
   {
-    for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
+    if ( fontGlyphRecordIt->mFontId == fontId )
     {
-      if ( mGlyphRecords[ i ].mImageId == imageId )
+      for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+            glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+            ++glyphRecordIt )
       {
-        mGlyphRecords.Remove( mGlyphRecords.Begin() + i );
-        return;
+        if ( glyphRecordIt->mImageId == imageId )
+        {
+          glyphRecordIt->mCount += delta;
+          if ( !glyphRecordIt->mCount )
+          {
+            mAtlasManager.Remove( glyphRecordIt->mImageId );
+            fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+          }
+          return;
+        }
       }
     }
   }
 }
 
-Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
-{
-  return mAtlasManager.GetPixelFormat( atlasId );
-}
-
 Material AtlasGlyphManager::GetMaterial( uint32_t atlasId ) const
 {
   return mAtlasManager.GetMaterial( atlasId );
@@ -193,13 +258,6 @@ Sampler AtlasGlyphManager::GetSampler( uint32_t atlasId ) const
   return mAtlasManager.GetSampler( atlasId );
 }
 
-const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
-{
-  mMetrics.mGlyphCount = mGlyphRecords.Size();
-  mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
-  return mMetrics;
-}
-
 } // namespace Internal
 
 } // namespace Toolkit
index 3b2b8af..9fe8ead 100644 (file)
@@ -49,11 +49,17 @@ class AtlasGlyphManager : public Dali::BaseObject
 {
 public:
 
-  struct GlyphRecord
+  struct GlyphRecordEntry
   {
-    Text::FontId mFontId;
     Text::GlyphIndex mIndex;
     uint32_t mImageId;
+    int32_t mCount;
+  };
+
+  struct FontGlyphRecord
+  {
+    Text::FontId mFontId;
+    Vector< GlyphRecordEntry > mGlyphRecords;
   };
 
   AtlasGlyphManager();
@@ -68,7 +74,8 @@ public:
   /**
    * @copydoc Toolkit::AtlasGlyphManager::Add
    */
-  void Add( const Text::GlyphInfo& glyph,
+  void Add( Text::FontId fontId,
+            const Text::GlyphInfo& glyph,
             const BufferImage& bitmap,
             Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
@@ -88,7 +95,7 @@ public:
   /**
    * @copydoc Toolkit::AtlasGlyphManager::Cached
    */
-  void Cached( Text::FontId fontId,
+  bool Cached( Text::FontId fontId,
                Text::GlyphIndex index,
                Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
@@ -103,14 +110,14 @@ public:
   void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
 
   /**
-   * @copydoc Toolkit::AtlasGlyphManager::Remove
+   * @copydoc Toolkit::AtlasGlyphManager::GetPixelFormat
    */
-  void Remove( uint32_t imageId );
+  Pixel::Format GetPixelFormat( uint32_t atlasId );
 
   /**
-   * @copydoc Toolkit::AtlasGlyphManager::GetPixelFormat
+   * @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount
    */
-  Pixel::Format GetPixelFormat( uint32_t atlasId );
+  void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
 
   /**
    * @copydoc Toolkit::AtlasGlyphManager::GetMaterial
@@ -146,7 +153,7 @@ public:
 private:
 
   Dali::Toolkit::AtlasManager mAtlasManager;          ///> Atlas Manager created by GlyphManager
-  Vector< GlyphRecord > mGlyphRecords;                ///> Cached glyph information
+  std::vector< FontGlyphRecord > mFontGlyphRecords;
   Toolkit::AtlasGlyphManager::Metrics mMetrics;       ///> Metrics to pass back on GlyphManager status
   Shader mEffectBufferShader;                         ///> Shader used to render drop shadow buffer textures
   Shader mShadowShader;                               ///> Shader used to render drop shadow into buffer
@@ -177,4 +184,4 @@ inline Internal::AtlasGlyphManager& GetImplementation(Toolkit::AtlasGlyphManager
 } // namespace Dali
 
 
- #endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
\ No newline at end of file
+ #endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
index 7292012..304a531 100644 (file)
@@ -69,11 +69,12 @@ AtlasGlyphManager::AtlasGlyphManager(Internal::AtlasGlyphManager *impl)
 {
 }
 
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+                             const Text::GlyphInfo& glyph,
                              const BufferImage& bitmap,
                              AtlasManager::AtlasSlot& slot )
 {
-  GetImplementation(*this).Add( glyph, bitmap, slot );
+  GetImplementation(*this).Add( fontId, glyph, bitmap, slot );
 }
 
 void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
@@ -91,11 +92,11 @@ void AtlasGlyphManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
   GetImplementation(*this).StitchMesh( first, second );
 }
 
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
                                 Text::GlyphIndex index,
                                 AtlasManager::AtlasSlot& slot )
 {
-  GetImplementation(*this).Cached( fontId, index, slot );
+  return GetImplementation(*this).Cached( fontId, index, slot );
 }
 
 void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
@@ -108,11 +109,6 @@ Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
   return GetImplementation(*this).GetAtlasSize( atlasId );
 }
 
-void AtlasGlyphManager::Remove( uint32_t imageId )
-{
-  GetImplementation(*this).Remove( imageId );
-}
-
 Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
 {
   return GetImplementation(*this).GetPixelFormat( atlasId );
@@ -133,6 +129,11 @@ const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
   return GetImplementation(*this).GetMetrics();
 }
 
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+{
+  GetImplementation(*this).AdjustReferenceCount( fontId, imageId, delta );
+}
+
 Shader AtlasGlyphManager::GetEffectBufferShader() const
 {
   return GetImplementation(*this).GetEffectBufferShader();
index 0f8468d..cda8fb6 100644 (file)
@@ -71,11 +71,13 @@ public:
   /**
    * @brief Ask Atlas Manager to add a glyph
    *
+   * @param[in] fontId fontId glyph comes from
    * @param[in] glyph glyph to add to an atlas
    * @param[in] bitmap bitmap to use for glyph addition
    * @param[out] slot information returned by atlas manager for addition
    */
-  void Add( const Text::GlyphInfo& glyph,
+  void Add( Text::FontId fontId,
+            const Text::GlyphInfo& glyph,
             const BufferImage& bitmap,
             AtlasManager::AtlasSlot& slot );
 
@@ -105,8 +107,10 @@ public:
    * @param[in] fontId The font that this glyph comes from
    * @param[in] index The GlyphIndex of this glyph
    * @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached )
+   *
+   * @return Whether glyph is cached or not ?
    */
-  void Cached( Text::FontId fontId,
+  bool Cached( Text::FontId fontId,
                Text::GlyphIndex index,
                AtlasManager::AtlasSlot& slot );
 
@@ -130,13 +134,6 @@ public:
   void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
 
   /**
-   * @brief Unreference an image from the atlas and remove from cache if no longer needed
-   *
-   * @param[in] imageId ID of the image
-   */
-  void Remove( uint32_t imageId );
-
-  /**
    * @brief Get the Pixel Format used by an atlas
    *
    * @param[in] atlasId Id of atlas to check
@@ -171,6 +168,15 @@ public:
   const Metrics& GetMetrics();
 
   /**
+   * @brief Adjust the reference count for an imageId and remove cache entry if it becomes free
+   *
+   * @param[in] fontId the font this image came from
+   * @param[in] imageId The imageId
+   * @param[in] delta adjustment to make to reference count
+   */
+  void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+
+  /**
    * @brief Get Shader used for rendering glyph effect buffers
    *
    * @return Handle of shader needed
index 1def1b1..457959f 100644 (file)
@@ -76,17 +76,24 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     uint32_t mMeshRecordIndex;
   };
 
-  struct AtlasRecord
+  struct MaxBlockSize
   {
-    uint32_t mImageId;
+    FontId mFontId;
+    uint32_t mNeededBlockWidth;
+    uint32_t mNeededBlockHeight;
+  };
+
+  struct CheckEntry
+  {
+    FontId mFontId;
     Text::GlyphIndex mIndex;
   };
 
-  struct MaxBlockSize
+  struct TextCacheEntry
   {
     FontId mFontId;
-    uint32_t mNeededBlockWidth;
-    uint32_t mNeededBlockHeight;
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
   };
 
   Impl()
@@ -112,6 +119,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
     Vector< Extent > extents;
+    TextCacheEntry textCacheEntry;
     mDepth = static_cast< int >( depth );
 
     float currentUnderlinePosition = ZERO;
@@ -125,10 +133,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       style = STYLE_DROP_SHADOW;
     }
 
-    if ( mImageIds.Size() )
+    if ( mTextCache.Size() )
     {
-      // Unreference any currently used glyphs
-      RemoveText();
+      // Update the glyph cache with any changes to current text
+      RemoveText( glyphs );
     }
 
     CalculateBlocksSize( glyphs );
@@ -178,17 +186,9 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
         const Vector2& position = positions[ i ];
         AtlasManager::Mesh2D newMesh;
-        mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
 
-        if ( slot.mImageId )
-        {
-          // This glyph already exists so generate mesh data plugging in our supplied position
-          mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-          mImageIds.PushBack( slot.mImageId );
-        }
-        else
+        if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
         {
-
           // Select correct size for new atlas if needed....?
           if ( lastFontId != glyph.fontId )
           {
@@ -231,16 +231,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker
             }
 
             // Locate a new slot for our glyph
-            mGlyphManager.Add( glyph, bitmap, slot );
-
-            // Generate mesh data for this quad, plugging in our supplied position
-            if ( slot.mImageId )
-            {
-              mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
-              mImageIds.PushBack( slot.mImageId );
-            }
+            mGlyphManager.Add( glyph.fontId, glyph, bitmap, slot );
           }
         }
+
+        // Generate mesh data for this quad, plugging in our supplied position
+        mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
+        textCacheEntry.mFontId = glyph.fontId;
+        textCacheEntry.mImageId = slot.mImageId;
+        textCacheEntry.mIndex = glyph.index;
+        mTextCache.PushBack( textCacheEntry );
+
         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
         StitchTextMesh( meshContainer,
                         newMesh,
@@ -282,7 +283,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           mActor = actor;
         }
       }
-      mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
     }
 #if defined(DEBUG_ENABLED)
     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
@@ -437,19 +437,56 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  // Unreference any glyphs that were used with this actor
-  void OffStageDisconnect( Dali::Actor actor )
+  void RemoveText( const Vector<GlyphInfo>& glyphs )
   {
-    RemoveText();
-  }
+    Vector< CheckEntry > checked;
+    CheckEntry checkEntry;
 
-  void RemoveText()
-  {
-    for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
+    for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
     {
-      mGlyphManager.Remove( mImageIds[ i ] );
+      uint32_t index = tCit->mIndex;
+      uint32_t fontId = tCit->mFontId;
+
+      // Check that this character has not already been checked...
+      bool wasChecked = false;
+      for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
+      {
+        if ( fontId == cEit->mFontId && index == cEit->mIndex )
+        {
+          wasChecked = true;
+        }
+      }
+
+      if ( !wasChecked )
+      {
+
+        int32_t newCount = 0;
+        int32_t oldCount = 0;
+
+        // How many times does this character occur in the old text ?
+        for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
+        {
+          if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
+          {
+            oldCount++;
+          }
+        }
+
+        // And how many times in the new ?
+        for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
+        {
+          if ( fontId == cGit->fontId && index == cGit->index )
+          {
+            newCount++;
+          }
+        }
+        mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
+        checkEntry.mIndex = index;
+        checkEntry.mFontId = fontId;
+        checked.PushBack( checkEntry );
+      }
     }
-    mImageIds.Resize( 0 );
+    mTextCache.Resize( 0 );
   }
 
   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
@@ -678,10 +715,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   Actor mActor;                                       ///< The actor parent which renders the text
   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
-  Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
   std::vector< uint32_t > mFace;                      ///> Face indices for a quad
+  Vector< TextCacheEntry > mTextCache;
   Property::Map mQuadVertexFormat;
   Property::Map mQuadIndexFormat;
   int mDepth;
@@ -737,5 +774,7 @@ AtlasRenderer::AtlasRenderer()
 
 AtlasRenderer::~AtlasRenderer()
 {
+  Vector< GlyphInfo > emptyGlyphs;
+  mImpl->RemoveText( emptyGlyphs );
   delete mImpl;
 }
index 3889793..466991b 100644 (file)
@@ -84,13 +84,6 @@ void SetLineBreakInfo( const Vector<Character>& text,
 #endif
 }
 
-void ReplaceLineBreakInfo( LogicalModel& model,
-                           CharacterIndex characterIndex,
-                           Length numberOfCharactersToRemove,
-                           Length numberOfCharactersToInsert )
-{
-}
-
 void SetWordBreakInfo( const Vector<Character>& text,
                        Vector<WordBreakInfo>& wordBreakInfo )
 {
@@ -126,13 +119,6 @@ void SetWordBreakInfo( const Vector<Character>& text,
 #endif
 }
 
-void ReplaceWordBreakInfo( LogicalModel& model,
-                           CharacterIndex characterIndex,
-                           Length numberOfCharactersToRemove,
-                           Length numberOfCharactersToInsert )
-{
-}
-
 } // namespace Text
 
 } // namespace Toolkit
index 949b1c9..4bbe5d5 100644 (file)
@@ -51,24 +51,6 @@ void SetLineBreakInfo( const Vector<Character>& text,
                        Vector<LineBreakInfo>& lineBreakInfo );
 
 /**
- * Replaces line break info.
- *
- * @pre The @p model needs to have a text set.
- *
- * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
- * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
- *
- * @param[in,out] model The text's logical model.
- * @param[in] characterIndex Index to the first character.
- * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
- * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
- */
-void ReplaceLineBreakInfo( LogicalModel& model,
-                           CharacterIndex characterIndex,
-                           Length numberOfCharactersToRemove,
-                           Length numberOfCharactersToInsert );
-
-/**
  * Sets word break info.
  *
  * - 0 is a WORD_BREAK.    Text can be broken into a new word.
@@ -80,24 +62,6 @@ void ReplaceLineBreakInfo( LogicalModel& model,
 void SetWordBreakInfo( const Vector<Character>& text,
                        Vector<WordBreakInfo>& wordBreakInfo );
 
-/**
- * Replaces word break info.
- *
- * @pre The @p model needs to have a text set.
- *
- * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
- * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
- *
- * @param[in,out] model The text's logical model.
- * @param[in] characterIndex Index to the first character.
- * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
- * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
- */
-void ReplaceWordBreakInfo( LogicalModel& model,
-                           CharacterIndex characterIndex,
-                           Length numberOfCharactersToRemove,
-                           Length numberOfCharactersToInsert );
-
 } // namespace Text
 
 } // namespace Toolkit
index c236d28..9ca8e9f 100644 (file)
@@ -225,14 +225,6 @@ void ShapeText( const Vector<Character>& text,
   glyphToCharacterMap.Resize( totalNumberOfGlyphs );
 }
 
-void ShapeText( const LogicalModel& logicalModel,
-                VisualModel& visualModel,
-                CharacterIndex characterIndex,
-                Length numberOfCharactersToRemove,
-                Length numberOfCharactersToInsert )
-{
-}
-
 } // namespace Text
 
 } // namespace Toolkit
index d423cc5..f07cf49 100644 (file)
@@ -56,29 +56,6 @@ void ShapeText( const Vector<Character>& text,
                 Vector<CharacterIndex>& glyphToCharacterMap,
                 Vector<Length>& charactersPerGlyph );
 
-/**
- * Replaces the shape info of the given range of characters.
- *
- * @pre The @p model needs to have a text set.
- * @pre The @p model needs to have the scripts set.
- * @pre The @p model needs to have the fonts set.
- * @pre The @p model needs to have the bidirectional info set.
- *
- * If the @p numberOfCharactersToRemove is zero, this operation is like an insert.
- * If the @p numberOfCharactersToInsert is zero, this operation is like a remove.
- *
- * @param[in] logicalModel The text's logical model.
- * @param[in,out] visualModel The text's logical model.
- * @param[in] characterIndex Index to the first character.
- * @param[in] numberOfCharactersToRemove The number of characters removed from the text.
- * @param[in] numberOfCharactersToInsert The number of characters inserted in the text.
- */
-void ShapeText( const LogicalModel& logicalModel,
-                VisualModel& visualModel,
-                CharacterIndex characterIndex,
-                Length numberOfCharactersToRemove,
-                Length numberOfCharactersToInsert );
-
 } // namespace Text
 
 } // namespace Toolkit
index e485be9..ede1531 100644 (file)
@@ -21,6 +21,8 @@
 namespace Dali
 {
 
+class Actor;
+
 namespace Toolkit
 {
 
@@ -45,6 +47,14 @@ public:
   virtual ~ControlInterface();
 
   /**
+   * @brief Add a decoration.
+   *
+   * @param[in] decoration The actor displaying a decoration.
+   * @param[in] needsClipping Whether the actor needs clipping.
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping ) = 0;
+
+  /**
    * @brief Called to request a text relayout.
    */
   virtual void RequestTextRelayout() = 0;
index 35c43b0..7a51b86 100644 (file)
@@ -128,14 +128,15 @@ EventData::EventData( DecoratorPtr decorator )
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
-  mGrabHandlePopupEnabled( false ),
-  mSelectionEnabled( false ),
+  mGrabHandlePopupEnabled( true ),
+  mSelectionEnabled( true ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
-  mScrollAfterUpdateCursorPosition( false )
+  mScrollAfterUpdatePosition( false ),
+  mScrollAfterDelete( false )
 {}
 
 EventData::~EventData()
@@ -159,28 +160,38 @@ bool Controller::Impl::ProcessInputEvents()
     {
       switch( iter->type )
       {
-      case Event::CURSOR_KEY_EVENT:
-      {
-        OnCursorKeyEvent( *iter );
-        break;
-      }
-      case Event::TAP_EVENT:
-      {
-        OnTapEvent( *iter );
-        break;
-      }
-      case Event::PAN_EVENT:
-      {
-        OnPanEvent( *iter );
-        break;
-      }
-      case Event::GRAB_HANDLE_EVENT:
-      case Event::LEFT_SELECTION_HANDLE_EVENT:
-      case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
-      {
-        OnHandleEvent( *iter );
-        break;
-      }
+        case Event::CURSOR_KEY_EVENT:
+        {
+          OnCursorKeyEvent( *iter );
+          break;
+        }
+        case Event::TAP_EVENT:
+        {
+          OnTapEvent( *iter );
+          break;
+        }
+        case Event::PAN_EVENT:
+        {
+          OnPanEvent( *iter );
+          break;
+        }
+        case Event::GRAB_HANDLE_EVENT:
+        case Event::LEFT_SELECTION_HANDLE_EVENT:
+        case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
+        {
+          OnHandleEvent( *iter );
+          break;
+        }
+        case Event::SELECT:
+        {
+          OnSelectEvent( *iter );
+          break;
+        }
+        case Event::SELECT_ALL:
+        {
+          OnSelectAllEvent();
+          break;
+        }
       }
     }
   }
@@ -192,48 +203,73 @@ bool Controller::Impl::ProcessInputEvents()
 
     UpdateCursorPosition();
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+    if( mEventData->mScrollAfterUpdatePosition )
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+      ScrollToMakePositionVisible( primaryCursorPosition );
+      mEventData->mScrollAfterUpdatePosition = false;
     }
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
-  else if( mEventData->mUpdateLeftSelectionPosition )
+  else if( mEventData->mScrollAfterDelete )
   {
-    UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
-
-    if( mEventData->mScrollAfterUpdateCursorPosition )
-    {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
-    }
-
+    ScrollTextToMatchCursor();
     mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateLeftSelectionPosition = false;
+    mEventData->mScrollAfterDelete = false;
   }
-  else if( mEventData->mUpdateRightSelectionPosition )
+  else
   {
-    UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+    bool leftScroll = false;
+    bool rightScroll = false;
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        const Vector2& leftHandlePosition = mEventData->mDecorator->GetPosition( LEFT_SELECTION_HANDLE );
+
+        ScrollToMakePositionVisible( leftHandlePosition );
+        leftScroll = true;
+      }
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateLeftSelectionPosition = false;
+    }
+
+    if( mEventData->mUpdateRightSelectionPosition )
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        const Vector2& rightHandlePosition = mEventData->mDecorator->GetPosition( RIGHT_SELECTION_HANDLE );
+
+        ScrollToMakePositionVisible( rightHandlePosition );
+        rightScroll = true;
+      }
+
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateRightSelectionPosition = false;
     }
 
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateRightSelectionPosition = false;
+    if( leftScroll || rightScroll )
+    {
+      mEventData->mScrollAfterUpdatePosition = false;
+    }
   }
 
   mEventData->mEventQueue.clear();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
 
-  bool decoratorUpdated = mEventData->mDecoratorUpdated;
+  const bool decoratorUpdated = mEventData->mDecoratorUpdated;
   mEventData->mDecoratorUpdated = false;
+
   return decoratorUpdated;
 }
 
@@ -416,7 +452,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
-    if( mLogicalModel->GetNumberOfCharacters() > mEventData->mPrimaryCursorPosition )
+    if( mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
     {
       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
     }
@@ -431,7 +467,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
 
   mEventData->mUpdateCursorPosition = true;
-  mEventData->mScrollAfterUpdateCursorPosition = true;
+  mEventData->mScrollAfterUpdatePosition = true;
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
@@ -456,12 +492,7 @@ void Controller::Impl::OnTapEvent( const Event& event )
       }
 
       mEventData->mUpdateCursorPosition = true;
-      mEventData->mScrollAfterUpdateCursorPosition = true;
-    }
-    else if( mEventData->mSelectionEnabled &&
-             ( 2u == tapCount ) )
-    {
-      RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
+      mEventData->mScrollAfterUpdatePosition = true;
     }
   }
 }
@@ -514,6 +545,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
   }
 
   const unsigned int state = event.p1.mUint;
+  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
 
   if( HANDLE_PRESSED == state )
   {
@@ -525,7 +557,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
-      ChangeState ( EventData::EDITING );
+      ChangeState ( EventData::GRAB_HANDLE_PANNING );
 
       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
       {
@@ -535,94 +567,389 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     }
     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mLeftSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
+
+        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                    mEventData->mRightSelectionPosition );
+
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
+
+        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                    mEventData->mRightSelectionPosition );
+
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
-  }
+  } // end ( HANDLE_PRESSED == state )
   else if( ( HANDLE_RELEASED == state ) ||
-           ( HANDLE_STOP_SCROLLING == state ) )
+           handleStopScrolling )
   {
-    if( mEventData->mGrabHandlePopupEnabled )
+    CharacterIndex handlePosition = 0u;
+    if( handleStopScrolling )
     {
-      ChangeState( EventData::EDITING_WITH_POPUP );
+      // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+      const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+      const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+
+      handlePosition = GetClosestCursorIndex( xPosition, yPosition );
     }
+
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
 
-      if( HANDLE_STOP_SCROLLING == state )
+      ChangeState( EventData::EDITING_WITH_POPUP );
+
+      if( handleStopScrolling )
       {
-        // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
-        const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
-        const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+        mEventData->mScrollAfterUpdatePosition = mEventData->mPrimaryCursorPosition != handlePosition;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
 
-        mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateLeftSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition);
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
+
+        if( mEventData->mUpdateLeftSelectionPosition )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
 
-        mEventData->mScrollAfterUpdateCursorPosition = true;
+          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                      mEventData->mRightSelectionPosition );
+        }
       }
     }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateRightSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
+
+        if( mEventData->mUpdateRightSelectionPosition )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                      mEventData->mRightSelectionPosition );
+        }
+      }
+    }
+
     mEventData->mDecoratorUpdated = true;
-  }
+  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
   else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
     const Vector2& actualSize = mVisualModel->GetActualSize();
+    const Vector2 currentScrollPosition = mEventData->mScrollPosition;
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
-   mEventData->mDecoratorUpdated = true;
+    if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
+    {
+      // Notify the decorator there is no more text to scroll.
+      // The decorator won't send more scroll events.
+      mEventData->mDecorator->NotifyEndOfScroll();
+    }
+    else
+    {
+      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;
+
+      if( Event::GRAB_HANDLE_EVENT == event.type )
+      {
+        ChangeState( EventData::GRAB_HANDLE_PANNING );
+
+        Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+
+        // Position the grag handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mControlSize.width;
+
+        // 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 if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+      {
+        // 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.
+
+        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;
+    }
+  } // end ( HANDLE_SCROLLING == state )
+}
+
+void Controller::Impl::OnSelectEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled )
+  {
+    // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+    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->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
+    mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+
+    mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
+                                               ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
   }
 }
 
-void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+void Controller::Impl::OnSelectAllEvent()
 {
   if( NULL == mEventData )
   {
-    // Nothing to do if there is no text input.
+    // Nothing to do if there is no text.
     return;
   }
 
-  // TODO - Find which word was selected
+  if( mEventData->mSelectionEnabled )
+  {
+    RepositionSelectionHandles( 0u,
+                                mLogicalModel->mText.Count() );
 
-  const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
-  const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
+  }
+}
 
-  const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
-  const Vector<Vector2>::SizeType positionCount = positions.Count();
+void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetreival )
+{
+  if( mEventData->mLeftSelectionPosition ==  mEventData->mRightSelectionPosition )
+  {
+    // Nothing to select if handles are in the same place.
+    selectedText="";
+    return;
+  }
 
-  // Guard against glyphs which did not fit inside the layout
-  const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
+  //Get start and end position of selection
+  uint32_t startOfSelectedText = mEventData->mLeftSelectionPosition;
+  uint32_t lengthOfSelectedText =  mEventData->mRightSelectionPosition - startOfSelectedText;
 
-  if( count )
+  // Validate the start and end selection points
+  if( ( startOfSelectedText >= 0 ) && (  ( startOfSelectedText + lengthOfSelectedText ) <=  mLogicalModel->mText.Count() ) )
   {
-    float primaryX   = positions[0].x + mEventData->mScrollPosition.x;
-    float secondaryX = positions[count-1].x + glyphs[count-1].width + mEventData->mScrollPosition.x;
+    //Get text as a UTF8 string
+    Vector<Character>& utf32Characters = mLogicalModel->mText;
+
+    Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
+
+    if ( deleteAfterRetreival  ) // Only delete text if copied successfully
+    {
+      // Delete text between handles
+      Vector<Character>& currentText = mLogicalModel->mText;
+
+      Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
+      Vector<Character>::Iterator last  = first + lengthOfSelectedText;
+      currentText.Erase( first, last );
+    }
+    mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition;
+    mEventData->mScrollAfterDelete = true;
+    mEventData->mDecoratorUpdated = true;
+  }
+}
 
-    // TODO - multi-line selection
-    const Vector<LineRun>& lines = mVisualModel->mLines;
-    float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
+bool Controller::Impl::CopyStringToClipboard( std::string& source )
+{
+  //Send string to clipboard
+  return ( mClipboard && mClipboard.SetItem( source ) );
+}
 
-    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,     primaryX, mEventData->mScrollPosition.y, height );
-    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryX, mEventData->mScrollPosition.y, height );
+void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
+{
+  std::string selectedText;
+  RetrieveSelection( selectedText, deleteAfterSending );
+  CopyStringToClipboard( selectedText );
+  ChangeState( EventData::EDITING );
+}
 
-    mEventData->mDecorator->ClearHighlights();
-    mEventData->mDecorator->AddHighlight( primaryX, mEventData->mScrollPosition.y, secondaryX, height + mEventData->mScrollPosition.y );
+void Controller::Impl::GetTextFromClipboard( unsigned int itemIndex, std::string& retreivedString )
+{
+  if ( mClipboard )
+  {
+    retreivedString =  mClipboard.GetItem( itemIndex );
   }
 }
 
+void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd )
+{
+  if( selectionStart == selectionEnd )
+  {
+    // Nothing to select if handles are in the same place.
+    return;
+  }
+
+  mEventData->mDecorator->ClearHighlights();
+
+  mEventData->mLeftSelectionPosition = selectionStart;
+  mEventData->mRightSelectionPosition = selectionEnd;
+
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  const GlyphInfo* const glyphsBuffer = mVisualModel->mGlyphs.Begin();
+  const Vector2* const positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+
+  // TODO: Better algorithm to create the highlight box.
+  // TODO: Multi-line.
+
+  const Vector<LineRun>& lines = mVisualModel->mLines;
+  const LineRun& firstLine = *lines.Begin();
+  const float height = firstLine.ascender + -firstLine.descender;
+
+  const bool indicesSwapped = ( selectionStart > selectionEnd );
+  if( indicesSwapped )
+  {
+    std::swap( selectionStart, selectionEnd );
+  }
+
+  GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
+  GlyphIndex glyphEnd = *( charactersToGlyphBuffer + ( selectionEnd - 1u ) ) + *( glyphsPerCharacterBuffer + ( selectionEnd - 1u ) ) - 1u;
+
+  mEventData->mDecorator->SwapSelectionHandlesEnabled( firstLine.direction != indicesSwapped );
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+
+  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  {
+    const GlyphInfo& glyph = *( glyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+
+    const float xPosition = position.x - glyph.xBearing + offset.x;
+    mEventData->mDecorator->AddHighlight( xPosition, offset.y, xPosition + glyph.advance, height );
+  }
+
+  CursorInfo primaryCursorInfo;
+  GetCursorPosition( mEventData->mLeftSelectionPosition,
+                     primaryCursorInfo );
+
+  CursorInfo secondaryCursorInfo;
+  GetCursorPosition( mEventData->mRightSelectionPosition,
+                     secondaryCursorInfo );
+
+  const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + offset;
+  const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + offset;
+
+  mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE, primaryPosition.x, primaryPosition.y, primaryCursorInfo.lineHeight );
+
+  mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryPosition.x, secondaryPosition.y, secondaryCursorInfo.lineHeight );
+
+  // Set the flag to update the decorator.
+  mEventData->mDecoratorUpdated = true;
+}
+
+void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  if( IsShowingPlaceholderText() )
+  {
+    // Nothing to do if there is the place-holder text.
+    return;
+  }
+
+  const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
+  const Length numberOfLines  = mVisualModel->mLines.Count();
+  if( 0 == numberOfGlyphs ||
+      0 == numberOfLines )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  // Find which word was selected
+  CharacterIndex selectionStart( 0 );
+  CharacterIndex selectionEnd( 0 );
+  FindSelectionIndices( visualX, visualY, selectionStart, selectionEnd );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
+
+  if( selectionStart == selectionEnd )
+  {
+    ChangeState( EventData::EDITING );
+    // Nothing to select. i.e. a white space, out of bounds
+    return;
+  }
+
+  RepositionSelectionHandles( selectionStart, selectionEnd );
+}
+
 void Controller::Impl::ChangeState( EventData::State newState )
 {
   if( NULL == mEventData )
@@ -652,6 +979,32 @@ void Controller::Impl::ChangeState( EventData::State newState )
       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+        if ( !IsClipboardEmpty() )
+        {
+          buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+        }
+
+        mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if ( EventData::SELECTION_CHANGED  == mEventData->mState )
+    {
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+        if (  !IsClipboardEmpty() )
+        {
+          buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+        }
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+        mEventData->mDecorator->SetPopupActive( true );
+      }
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING == mEventData->mState )
@@ -665,6 +1018,10 @@ void Controller::Impl::ChangeState( EventData::State newState )
       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
@@ -674,18 +1031,58 @@ void Controller::Impl::ChangeState( EventData::State newState )
       {
         mEventData->mDecorator->StartCursorBlink();
       }
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       if( mEventData->mSelectionEnabled )
       {
-        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      }
+      else
+      {
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
       }
       if( mEventData->mGrabHandlePopupEnabled )
       {
+        TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
+
+        if ( !IsClipboardEmpty() )
+        {
+          buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+        }
+
+        mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
         mEventData->mDecorator->SetPopupActive( true );
       }
       mEventData->mDecoratorUpdated = true;
     }
+    else if ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+      mEventData->mDecorator->StopCursorBlink();
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if ( EventData::GRAB_HANDLE_PANNING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
   }
 }
 
@@ -707,9 +1104,49 @@ LineIndex Controller::Impl::GetClosestLine( float y ) const
     }
   }
 
+  if( lineIndex == 0 )
+  {
+    return 0;
+  }
+
   return lineIndex-1;
 }
 
+void Controller::Impl::FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex )
+{
+  CharacterIndex hitCharacter = GetClosestCursorIndex( visualX, visualY );
+  if( hitCharacter >= mLogicalModel->mText.Count() )
+  {
+    // Selection out of bounds.
+    return;
+  }
+
+  startIndex = hitCharacter;
+  endIndex = hitCharacter;
+
+  if( !TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] ) )
+  {
+    // Find the start and end of the text
+    for( startIndex = hitCharacter; startIndex > 0; --startIndex )
+    {
+      Character charCode = mLogicalModel->mText[ startIndex-1 ];
+      if( TextAbstraction::IsWhiteSpace( charCode ) )
+      {
+        break;
+      }
+    }
+    const CharacterIndex pastTheEnd = mLogicalModel->mText.Count();
+    for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex )
+    {
+      Character charCode = mLogicalModel->mText[ endIndex ];
+      if( TextAbstraction::IsWhiteSpace( charCode ) )
+      {
+        break;
+      }
+    }
+  }
+}
+
 CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
                                                         float visualY )
 {
@@ -780,9 +1217,10 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
     const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
 
-    const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
+    // Find the mid-point of the area containing the glyph
+    const float glyphCenter = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
 
-    if( visualX < glyphX )
+    if( visualX < glyphCenter )
     {
       matched = true;
       break;
@@ -796,7 +1234,9 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
     visualIndex = endCharacter;
   }
 
-  return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  logicalIndex = hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p closest visualIndex %d logicalIndex %d\n", this, visualIndex, logicalIndex );
+  return logicalIndex;
 }
 
 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
@@ -806,7 +1246,7 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 
   // Check if the logical position is the first or the last one of the text.
   const bool isFirstPosition = 0u == logical;
-  const bool isLastPosition = mLogicalModel->GetNumberOfCharacters() == logical;
+  const bool isLastPosition = mLogicalModel->mText.Count() == logical;
 
   if( isFirstPosition && isLastPosition )
   {
@@ -1214,27 +1654,19 @@ void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
   }
 }
 
-void Controller::Impl::ScrollToMakeCursorVisible()
+void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
-
   Vector2 offset;
   bool updateDecorator = false;
-  if( primaryCursorPosition.x < 0.f )
+  if( position.x < 0.f )
   {
-    offset.x = -primaryCursorPosition.x;
+    offset.x = -position.x;
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
-  else if( primaryCursorPosition.x > mControlSize.width )
+  else if( position.x > mControlSize.width )
   {
-    offset.x = mControlSize.width - primaryCursorPosition.x;
+    offset.x = mControlSize.width - position.x;
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
@@ -1247,6 +1679,57 @@ void Controller::Impl::ScrollToMakeCursorVisible()
   // TODO : calculate the vertical scroll.
 }
 
+void Controller::Impl::ScrollTextToMatchCursor()
+{
+  // Get the current cursor position in decorator coords.
+  const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+  // Calculate the new cursor position.
+  CursorInfo cursorInfo;
+  GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                     cursorInfo );
+
+  // Calculate the offset to match the cursor position before the character was deleted.
+  mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x;
+
+  ClampHorizontalScroll( mVisualModel->GetActualSize() );
+  bool updateCursorPosition = true;
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+
+  if( updateCursorPosition )
+  {
+    // Sets the cursor position.
+    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                         cursorPosition.x,
+                                         cursorPosition.y,
+                                         cursorInfo.primaryCursorHeight,
+                                         cursorInfo.lineHeight );
+
+    // Sets the grab handle position.
+    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                         cursorPosition.x,
+                                         cursorPosition.y,
+                                         cursorInfo.lineHeight );
+
+    if( cursorInfo.isSecondaryCursor )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
+      mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                           cursorInfo.secondaryPosition.x + offset.x,
+                                           cursorInfo.secondaryPosition.y + offset.y,
+                                           cursorInfo.secondaryCursorHeight,
+                                           cursorInfo.lineHeight );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+    }
+    else
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    }
+  }
+}
+
 void Controller::Impl::RequestRelayout()
 {
   mControlInterface.RequestTextRelayout();
index ab2764c..880004a 100644 (file)
@@ -19,8 +19,9 @@
  */
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/adaptor-framework/clipboard.h>
 #include <dali/devel-api/adaptor-framework/imf-manager.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
@@ -47,7 +48,9 @@ struct Event
     PAN_EVENT,
     GRAB_HANDLE_EVENT,
     LEFT_SELECTION_HANDLE_EVENT,
-    RIGHT_SELECTION_HANDLE_EVENT
+    RIGHT_SELECTION_HANDLE_EVENT,
+    SELECT,
+    SELECT_ALL
   };
 
   union Param
@@ -99,8 +102,11 @@ struct EventData
   {
     INACTIVE,
     SELECTING,
+    SELECTION_CHANGED,
     EDITING,
-    EDITING_WITH_POPUP
+    EDITING_WITH_POPUP,
+    GRAB_HANDLE_PANNING,
+    SELECTION_HANDLE_PANNING
   };
 
   EventData( DecoratorPtr decorator );
@@ -133,19 +139,20 @@ struct EventData
   CharacterIndex     mPreEditStartPosition;    ///< Used to remove the pre-edit text if necessary.
   Length             mPreEditLength;           ///< Used to remove the pre-edit text if necessary.
 
-  bool mIsShowingPlaceholderText           : 1;   ///< True if the place-holder text is being displayed.
-  bool mPreEditFlag                        : 1;   ///< True if the model contains text in pre-edit state.
-  bool mDecoratorUpdated                   : 1;   ///< True if the decorator was updated during event processing.
-  bool mCursorBlinkEnabled                 : 1;   ///< True if cursor should blink when active.
-  bool mGrabHandleEnabled                  : 1;   ///< True if grab handle is enabled.
-  bool mGrabHandlePopupEnabled             : 1;   ///< True if the grab handle popu-up should be shown.
-  bool mSelectionEnabled                   : 1;   ///< True if selection handles, highlight etc. are enabled.
-  bool mHorizontalScrollingEnabled         : 1;   ///< True if horizontal scrolling is enabled.
-  bool mVerticalScrollingEnabled           : 1;   ///< True if vertical scrolling is enabled.
-  bool mUpdateCursorPosition               : 1;   ///< True if the visual position of the cursor must be recalculated.
-  bool mUpdateLeftSelectionPosition        : 1;   ///< True if the visual position of the left selection handle must be recalculated.
-  bool mUpdateRightSelectionPosition       : 1;   ///< True if the visual position of the right selection handle must be recalculated.
-  bool mScrollAfterUpdateCursorPosition    : 1;   ///< Whether to scroll after the cursor position is updated.
+  bool mIsShowingPlaceholderText        : 1;   ///< True if the place-holder text is being displayed.
+  bool mPreEditFlag                     : 1;   ///< True if the model contains text in pre-edit state.
+  bool mDecoratorUpdated                : 1;   ///< True if the decorator was updated during event processing.
+  bool mCursorBlinkEnabled              : 1;   ///< True if cursor should blink when active.
+  bool mGrabHandleEnabled               : 1;   ///< True if grab handle is enabled.
+  bool mGrabHandlePopupEnabled          : 1;   ///< True if the grab handle popu-up should be shown.
+  bool mSelectionEnabled                : 1;   ///< True if selection handles, highlight etc. are enabled.
+  bool mHorizontalScrollingEnabled      : 1;   ///< True if horizontal scrolling is enabled.
+  bool mVerticalScrollingEnabled        : 1;   ///< True if vertical scrolling is enabled.
+  bool mUpdateCursorPosition            : 1;   ///< True if the visual position of the cursor must be recalculated.
+  bool mUpdateLeftSelectionPosition     : 1;   ///< True if the visual position of the left selection handle must be recalculated.
+  bool mUpdateRightSelectionPosition    : 1;   ///< True if the visual position of the right selection handle must be recalculated.
+  bool mScrollAfterUpdatePosition       : 1;   ///< Whether to scroll after the cursor position is updated.
+  bool mScrollAfterDelete               : 1;   ///< Whether to scroll after delete characters.
 };
 
 struct ModifyEvent
@@ -194,6 +201,7 @@ struct Controller::Impl
     mFontDefaults( NULL ),
     mEventData( NULL ),
     mFontClient(),
+    mClipboard(),
     mView(),
     mLayoutEngine(),
     mModifyEvents(),
@@ -208,6 +216,7 @@ struct Controller::Impl
     mVisualModel  = VisualModel::New();
 
     mFontClient = TextAbstraction::FontClient::Get();
+    mClipboard = Clipboard::Get();
 
     mView.SetVisualModel( mVisualModel );
 
@@ -302,6 +311,12 @@ struct Controller::Impl
     ClearPreEditFlag();
   }
 
+  bool IsClipboardEmpty()
+  {
+    bool result( mClipboard && mClipboard.NumberOfItems() );
+    return !result; // // If NumberOfItems greater than 0, return false
+  }
+
   void UpdateModel( OperationsMask operationsRequired );
 
   /**
@@ -320,12 +335,27 @@ struct Controller::Impl
 
   void OnHandleEvent( const Event& event );
 
+  void OnSelectEvent( const Event& event );
+
+  void OnSelectAllEvent();
+
+  void RetrieveSelection( std::string& selectedText, bool deleteAfterRetreival );
+
+  bool CopyStringToClipboard( std::string& source );
+
+  void SendSelectionToClipboard( bool deleteAfterSending );
+
+  void GetTextFromClipboard( unsigned int itemIndex, std::string& retreivedString );
+
+  void RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd );
   void RepositionSelectionHandles( float visualX, float visualY );
 
   void ChangeState( EventData::State newState );
 
   LineIndex GetClosestLine( float y ) const;
 
+  void FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex );
+
   /**
    * @brief Retrieves the cursor's logical position for a given touch point x,y
    *
@@ -392,11 +422,23 @@ struct Controller::Impl
   void ClampVerticalScroll( const Vector2& actualSize );
 
   /**
+   * @brief Scrolls the text to make a position visible.
+   *
+   * @pre mEventData must not be NULL. (there is a text-input or selection capabilities).
+   *
+   * @param[in] position A position in decorator coords.
+   *
+   * This method is called after inserting text, moving the cursor with the grab handle or the keypad,
+   * or moving the selection handles.
+   */
+  void ScrollToMakePositionVisible( const Vector2& position );
+
+  /**
    * @brief Scrolls the text to make the cursor visible.
    *
-   * This method is called after inserting, deleting or moving the cursor with the keypad.
+   * This method is called after deleting text.
    */
-  void ScrollToMakeCursorVisible();
+  void ScrollTextToMatchCursor();
 
   ControlInterface& mControlInterface;     ///< Reference to the text controller.
   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
@@ -404,6 +446,7 @@ struct Controller::Impl
   FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
   EventData* mEventData;                   ///< Avoid allocating everything for text input until EnableTextInput().
   TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
+  Clipboard mClipboard;                   ///< Handle to the system clipboard
   View mView;                              ///< The view interface to the rendering back-end.
   LayoutEngine mLayoutEngine;              ///< The layout engine.
   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
index 889ca68..b55a543 100644 (file)
@@ -47,6 +47,12 @@ const float MAX_FLOAT = std::numeric_limits<float>::max();
 
 const std::string EMPTY_STRING("");
 
+float ConvertToEven( float value )
+{
+  int intValue(static_cast<int>( value ));
+  return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
+}
+
 } // namespace
 
 namespace Dali
@@ -76,6 +82,8 @@ void Controller::SetText( const std::string& text )
   // Remove the previously set text
   ResetText();
 
+  CharacterIndex lastCursorIndex = 0u;
+
   if( !text.empty() )
   {
     //  Convert text into UTF-32
@@ -93,11 +101,8 @@ void Controller::SetText( const std::string& text )
     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
 
-    // Reset the cursor position
-    if( mImpl->mEventData )
-    {
-      mImpl->mEventData->mPrimaryCursorPosition = characterCount;
-    }
+    // To reset the cursor position
+    lastCursorIndex = characterCount;
 
     // Update the rest of the model during size negotiation
     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
@@ -113,6 +118,12 @@ void Controller::SetText( const std::string& text )
     ShowPlaceholderText();
   }
 
+  // Resets the cursor position.
+  ResetCursorPosition( lastCursorIndex );
+
+  // Scrolls the text to make the cursor visible.
+  ResetScrollPosition();
+
   mImpl->RequestRelayout();
 
   if( mImpl->mEventData )
@@ -332,8 +343,7 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars )
       numberOfChars = currentText.Count() - cursorIndex;
     }
 
-    if( cursorIndex >= 0 &&
-        (cursorIndex + numberOfChars) <= currentText.Count() )
+    if( (cursorIndex + numberOfChars) <= currentText.Count() )
     {
       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
       Vector<Character>::Iterator last  = first + numberOfChars;
@@ -529,6 +539,9 @@ Vector3 Controller::GetNaturalSize()
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
   }
 
+  naturalSize.x = ConvertToEven( naturalSize.x );
+  naturalSize.y = ConvertToEven( naturalSize.y );
+
   return naturalSize;
 }
 
@@ -586,9 +599,9 @@ bool Controller::Relayout( const Size& size )
   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
   {
     bool glyphsRemoved( false );
-    if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
+    if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
     {
-      mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
+      mImpl->mVisualModel->mGlyphPositions.Clear();
       glyphsRemoved = true;
     }
     // Not worth to relayout if width or height is equal to zero.
@@ -672,12 +685,6 @@ void Controller::ResetText()
   mImpl->mLogicalModel->mText.Clear();
   ClearModelData();
 
-  // Reset the cursor position
-  if( mImpl->mEventData )
-  {
-    mImpl->mEventData->mPrimaryCursorPosition = 0;
-  }
-
   // We have cleared everything including the placeholder-text
   mImpl->PlaceholderCleared();
 
@@ -688,6 +695,32 @@ void Controller::ResetText()
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
 
+void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
+{
+  // Reset the cursor position
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
+
+    // Update the cursor if it's in editing mode.
+    if( ( EventData::EDITING == mImpl->mEventData->mState ) ||
+        ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) )
+    {
+      mImpl->mEventData->mUpdateCursorPosition = true;
+    }
+  }
+}
+
+void Controller::ResetScrollPosition()
+{
+  if( NULL != mImpl->mEventData )
+  {
+    // Reset the scroll position.
+    mImpl->mEventData->mScrollPosition = Vector2::ZERO;
+    mImpl->mEventData->mScrollAfterUpdatePosition = true;
+  }
+}
+
 void Controller::TextReplacedEvent()
 {
   // Reset buffers.
@@ -725,7 +758,7 @@ void Controller::TextInsertedEvent()
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
   mImpl->mEventData->mUpdateCursorPosition = true;
-  mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+  mImpl->mEventData->mScrollAfterUpdatePosition = true;
 }
 
 void Controller::TextDeletedEvent()
@@ -747,8 +780,7 @@ void Controller::TextDeletedEvent()
                                                            REORDER );
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
-  mImpl->mEventData->mUpdateCursorPosition = true;
-  mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+  mImpl->mEventData->mScrollAfterDelete = true;
 }
 
 bool Controller::DoRelayout( const Size& size,
@@ -767,7 +799,7 @@ bool Controller::DoRelayout( const Size& size,
     // after the first time the text has been laid out.
     // Fill the vectors again.
 
-    Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
+    Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
 
     if( 0u == numberOfGlyphs )
     {
@@ -827,7 +859,7 @@ bool Controller::DoRelayout( const Size& size,
         if( 0u != bidirectionalInfo.Count() )
         {
           // Get the lines
-          const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
+          const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
 
           // Reorder the lines.
           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
@@ -868,17 +900,6 @@ bool Controller::DoRelayout( const Size& size,
         }
       } // REORDER
 
-      // TODO: I'm working on a patch that changes the LayoutEngine::Align() method.
-      //       The layoutParameters is not needed and this call can be moved outside the if().
-      //       Then there is no need to do the layout again to change the alignment.
-      if( ALIGN & operations )
-      {
-        mImpl->mLayoutEngine.Align( layoutParameters,
-                                    layoutSize,
-                                    lines,
-                                    glyphPositions );
-      }
-
       // Sets the actual size.
       if( UPDATE_ACTUAL_SIZE & operations )
       {
@@ -891,6 +912,17 @@ bool Controller::DoRelayout( const Size& size,
     layoutSize = mImpl->mVisualModel->GetActualSize();
   }
 
+  if( ALIGN & operations )
+  {
+    // The laid-out lines.
+    Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
+
+    mImpl->mLayoutEngine.Align( layoutSize,
+                                lines );
+
+    viewUpdated = true;
+  }
+
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
   return viewUpdated;
 }
@@ -929,15 +961,7 @@ void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment align
     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
 
     // Set the flag to redo the alignment operation.
-    // TODO : Is not needed re-layout and reorder again but with the current implementation it is.
-    //        Im working on a different patch to fix an issue with the alignment. When that patch
-    //        is in, this issue can be fixed.
-    const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
-                                                                          UPDATE_ACTUAL_SIZE |
-                                                                          ALIGN              |
-                                                                          REORDER );
-
-    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
 
     mImpl->RequestRelayout();
   }
@@ -1114,28 +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() )
-        {
-          ShowPlaceholderText();
-          mImpl->mEventData->mUpdateCursorPosition = true;
-        }
-        else
-        {
-          mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
-        }
-
-        textChanged = true;
-      }
+      textChanged = BackspaceKeyEvent();
     }
     else
     {
@@ -1145,7 +1148,6 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->ClearPreEditFlag();
 
       InsertText( keyString, COMMIT );
-
       textChanged = true;
     }
 
@@ -1165,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" )
@@ -1176,14 +1178,25 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   Vector<Character> utf32Characters;
   Length characterCount( 0u );
 
-  if( ! text.empty() )
+  // Remove the previous IMF pre-edit (predicitive text)
+  if( mImpl->mEventData &&
+      mImpl->mEventData->mPreEditFlag &&
+      0 != mImpl->mEventData->mPreEditLength )
   {
-    // The placeholder text is no longer needed
-    if( mImpl->IsShowingPlaceholderText() )
-    {
-      ResetText();
-    }
+    CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
+    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() )
+  {
     //  Convert text into UTF-32
     utf32Characters.Resize( text.size() );
 
@@ -1199,22 +1212,17 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
   }
 
-  if( 0u != utf32Characters.Count() )
+  if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
   {
+    // The placeholder text is no longer needed
+    if( mImpl->IsShowingPlaceholderText() )
+    {
+      ResetText();
+    }
+
     // Handle the IMF (predicitive text) state changes
     if( mImpl->mEventData )
     {
-      if( mImpl->mEventData->mPreEditFlag &&
-          0 != mImpl->mEventData->mPreEditLength )
-      {
-        // Remove previous pre-edit text
-        CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
-        removedPreEdit = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
-
-        mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
-        mImpl->mEventData->mPreEditLength = 0;
-      }
-
       if( COMMIT == type )
       {
         // IMF manager is no longer handling key-events
@@ -1237,7 +1245,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
       }
     }
 
-    const Length numberOfCharactersInModel = mImpl->mLogicalModel->GetNumberOfCharacters();
+    const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
 
     // Restrict new text to fit within Maximum characters setting
     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
@@ -1262,8 +1270,16 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
   }
 
-  if( removedPreEdit ||
-      0 != utf32Characters.Count() )
+  if( 0u == mImpl->mLogicalModel->mText.Count() &&
+      mImpl->IsPlaceholderAvailable() )
+  {
+    // Show place-holder if empty after removing the pre-edit text
+    ShowPlaceholderText();
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    mImpl->ClearPreEditFlag();
+  }
+  else if( removedPrevious ||
+           0 != utf32Characters.Count() )
   {
     // Queue an inserted event
     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
@@ -1280,48 +1296,65 @@ 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" );
 
   if( NULL != mImpl->mEventData )
   {
+    const bool isShowingPlaceholderText = mImpl->IsShowingPlaceholderText();
     if( 1u == tapCount )
     {
       bool tapDuringEditMode( EventData::EDITING == mImpl->mEventData->mState );
 
-      if( ! mImpl->IsShowingPlaceholderText() &&
-          EventData::EDITING == mImpl->mEventData->mState )
+      if( !isShowingPlaceholderText && tapDuringEditMode )
       {
-        // Grab handle is not shown until a tap is received whilst EDITING
-        if( tapDuringEditMode )
-        {
-          mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
-        }
+        mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
         mImpl->mEventData->mDecorator->SetPopupActive( false );
       }
 
       mImpl->ChangeState( EventData::EDITING );
+
+      // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
+      if( mImpl->mEventData )
+      {
+        Event event( Event::TAP_EVENT );
+        event.p1.mUint = tapCount;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+        mImpl->mEventData->mEventQueue.push_back( event );
+
+        mImpl->RequestRelayout();
+      }
     }
-    else if( mImpl->mEventData->mSelectionEnabled &&
+    else if( !isShowingPlaceholderText &&
+             mImpl->mEventData->mSelectionEnabled &&
              ( 2u == tapCount ) )
     {
-      mImpl->ChangeState( EventData::SELECTING );
+      SelectEvent( x, y, false );
     }
   }
 
-  // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
-  if( mImpl->mEventData )
-  {
-    Event event( Event::TAP_EVENT );
-    event.p1.mUint = tapCount;
-    event.p2.mFloat = x;
-    event.p3.mFloat = y;
-    mImpl->mEventData->mEventQueue.push_back( event );
-
-    mImpl->RequestRelayout();
-  }
-
   // Reset keyboard as tap event has occurred.
   mImpl->ResetImfManager();
 }
@@ -1342,9 +1375,49 @@ void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
   }
 }
 
-void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
+void Controller::SelectEvent( float x, float y, bool selectAll )
+{
+  if( mImpl->mEventData )
+  {
+    if ( mImpl->mEventData->mState == EventData::SELECTING )
+    {
+      mImpl->ChangeState( EventData::SELECTION_CHANGED );
+    }
+    else
+    {
+      mImpl->ChangeState( EventData::SELECTING );
+    }
+
+    if( selectAll )
+    {
+      Event event( Event::SELECT_ALL );
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+    else
+    {
+      Event event( Event::SELECT );
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+
+    mImpl->RequestRelayout();
+  }
+}
+
+void Controller::GetTargetSize( Vector2& targetSize )
 {
-  DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
+  targetSize = mImpl->mControlSize;
+}
+
+void Controller::AddDecoration( Actor& actor, bool needsClipping )
+{
+  mImpl->mControlInterface.AddDecoration( actor, needsClipping );
+}
+
+void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
 
   if( mImpl->mEventData )
   {
@@ -1390,6 +1463,77 @@ void Controller::HandleEvent( HandleType handleType, HandleState state, float x,
   }
 }
 
+void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
+{
+  if( NULL == mImpl->mEventData )
+  {
+    return;
+  }
+
+  switch( button )
+  {
+    case Toolkit::TextSelectionPopup::CUT:
+    {
+      mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
+      mImpl->mOperationsPending = ALL_OPERATIONS;
+      if( 0u != mImpl->mLogicalModel->mText.Count() ||
+          !mImpl->IsPlaceholderAvailable() )
+      {
+        mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+      }
+      else
+      {
+        ShowPlaceholderText();
+        mImpl->mEventData->mUpdateCursorPosition = true;
+      }
+      mImpl->RequestRelayout();
+      mImpl->mControlInterface.TextChanged();
+      break;
+    }
+    case Toolkit::TextSelectionPopup::COPY:
+    {
+      mImpl->SendSelectionToClipboard( false ); // Text not modified
+      mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
+      break;
+    }
+    case Toolkit::TextSelectionPopup::PASTE:
+    {
+      std::string stringToPaste("");
+      mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
+      InsertText( stringToPaste, Text::Controller::COMMIT );
+      mImpl->ChangeState( EventData::EDITING );
+      mImpl->RequestRelayout();
+      break;
+    }
+    case Toolkit::TextSelectionPopup::SELECT:
+    {
+      const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+      if( mImpl->mEventData->mSelectionEnabled  )
+      {
+        // Creates a SELECT event.
+        SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
+      }
+      break;
+    }
+    case Toolkit::TextSelectionPopup::SELECT_ALL:
+    {
+      // Creates a SELECT_ALL event
+      SelectEvent( 0.f, 0.f, true );
+      break;
+    }
+    case Toolkit::TextSelectionPopup::CLIPBOARD:
+    {
+      break;
+    }
+    case Toolkit::TextSelectionPopup::NONE:
+    {
+      // Nothing to do.
+      break;
+    }
+  }
+}
+
 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
 {
   bool update( false );
@@ -1461,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 8a780a9..2f83407 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali/public-api/object/ref-object.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
 #include <dali-toolkit/internal/text/decorator/text-decorator.h>
 #include <dali-toolkit/internal/text/font-run.h>
 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
@@ -67,9 +68,11 @@ enum PlaceholderType
  * It provides a view of the text that can be used by rendering back-ends.
  *
  * For selectable/editable UI controls, the controller handles input events from the UI control
- * and decorations (grab handles etc) via an observer interface.
+ * and decorations (grab handles etc) via the Decorator::ControllerInterface interface.
+ *
+ * The text selection popup button callbacks are as well handled via the TextSelectionPopupCallbackInterface interface.
  */
-class Controller : public RefObject, public Decorator::Observer
+class Controller : public RefObject, public Decorator::ControllerInterface, public TextSelectionPopupCallbackInterface
 {
 public:
 
@@ -135,7 +138,7 @@ public:
   void GetText( std::string& text ) const;
 
   /**
-   * @brief Replaces any placeholder text previously set.
+   * @brief Remove a given number of characters
    *
    * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
    * @param[in] numberOfChars The number of characters to delete from the cursorOffset.
@@ -379,6 +382,18 @@ public:
   void ResetText();
 
   /**
+   * @brief Used to reset the cursor position after setting a new text.
+   *
+   * @param[in] cursorIndex Where to place the cursor.
+   */
+  void ResetCursorPosition( CharacterIndex cursorIndex );
+
+  /**
+   * @brief Used to reset the scroll position after setting a new text.
+   */
+  void ResetScrollPosition();
+
+  /**
    * @brief Used to process an event queued from SetText()
    */
   void TextReplacedEvent();
@@ -462,17 +477,17 @@ public:
   // Text-input Event Queuing
 
   /**
-   * @brief Caller by editable UI controls when keyboard focus is gained.
+   * @brief Called by editable UI controls when keyboard focus is gained.
    */
   void KeyboardFocusGainEvent();
 
   /**
-   * @brief Caller by editable UI controls when focus is lost.
+   * @brief Called by editable UI controls when focus is lost.
    */
   void KeyboardFocusLostEvent();
 
   /**
-   * @brief Caller by editable UI controls when key events are received.
+   * @brief Called by editable UI controls when key events are received.
    *
    * @param[in] event The key event.
    * @param[in] type Used to distinguish between regular key events and IMF events.
@@ -480,7 +495,7 @@ public:
   bool KeyEvent( const Dali::KeyEvent& event );
 
   /**
-   * @brief Caller by editable UI controls when key events are received.
+   * @brief Called by editable UI controls when key events are received.
    *
    * @param[in] text The text to insert.
    * @param[in] type Used to distinguish between regular key events and IMF events.
@@ -488,7 +503,13 @@ public:
   void InsertText( const std::string& text, InsertType type );
 
   /**
-   * @brief Caller by editable UI controls when a tap gesture occurs.
+   * @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.
    * @param[in] y The y position relative to the top-left of the parent control.
@@ -496,7 +517,7 @@ public:
   void TapEvent( unsigned int tapCount, float x, float y );
 
   /**
-   * @brief Caller by editable UI controls when a pan gesture occurs.
+   * @brief Called by editable UI controls when a pan gesture occurs.
    *
    * @param[in] state The state of the gesture.
    * @param[in] displacement This distance panned since the last pan gesture.
@@ -504,9 +525,15 @@ public:
   void PanEvent( Gesture::State state, const Vector2& displacement );
 
   /**
-   * @copydoc Dali::Toolkit::Text::Decorator::Observer::HandleEvent()
+   * @brief Creates a selection event.
+   *
+   * It could be called from the TapEvent (double tap) or when the text selection popup's sellect all button is pressed.
+   *
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   * @param[in] selectAll Whether the whole text is selected.
    */
-  virtual void HandleEvent( HandleType handle, HandleState state, float x, float y );
+  void SelectEvent( float x, float y, bool selectAll );
 
   /**
    * @brief Event received from IMF manager
@@ -517,6 +544,26 @@ public:
    */
   ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
 
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
+   */
+  virtual void GetTargetSize( Vector2& targetSize );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::DecorationEvent()
+   */
+  virtual void DecorationEvent( HandleType handle, HandleState state, float x, float y );
+
+  /**
+   * @copydoc Dali::Toolkit::TextSelectionPopup::TextPopupButtonCallbackInterface::TextPopupButtonTouched()
+   */
+  virtual void TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button );
+
 protected:
 
   /**
@@ -527,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 976635a..34c3f32 100644 (file)
@@ -67,7 +67,7 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
     // If ellipsis is enabled, the number of glyphs the layout engine has laid out may be less than 'numberOfGlyphs'.
     // Check the last laid out line to know if the layout engine elided some text.
 
-    const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
+    const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
     if( numberOfLines > 0u )
     {
       const LineRun& lastLine = *( mImpl->mVisualModel->mLines.Begin() + ( numberOfLines - 1u ) );
@@ -92,6 +92,48 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
                                               glyphIndex,
                                               numberOfLaidOutGlyphs );
 
+      // Get the lines for the given range of glyphs.
+      // The lines contain the alignment offset which needs to be added to the glyph's position.
+      LineIndex firstLine = 0u;
+      Length numberOfLines = 0u;
+      mImpl->mVisualModel->GetNumberOfLines( glyphIndex,
+                                             numberOfLaidOutGlyphs,
+                                             firstLine,
+                                             numberOfLines );
+
+      Vector<LineRun> lines;
+      lines.Resize( numberOfLines );
+      LineRun* lineBuffer = lines.Begin();
+
+      mImpl->mVisualModel->GetLinesOfGlyphRange( lineBuffer,
+                                                 glyphIndex,
+                                                 numberOfLaidOutGlyphs );
+
+      // Get the first line for the given glyph range.
+      LineIndex lineIndex = firstLine;
+      LineRun* line = lineBuffer + lineIndex;
+
+      // Index of the last glyph of the line.
+      GlyphIndex lastGlyphIndexOfLine = line->glyphIndex + line->numberOfGlyphs - 1u;
+
+      // Add the alignment offset to the glyph's position.
+      for( Length index = 0u; index < numberOfLaidOutGlyphs; ++index )
+      {
+        ( *( glyphPositions + index ) ).x += line->alignmentOffset;
+
+        if( lastGlyphIndexOfLine == index )
+        {
+          // Get the next line.
+          ++lineIndex;
+
+          if( lineIndex < numberOfLines )
+          {
+            line = lineBuffer + lineIndex;
+            lastGlyphIndexOfLine = line->glyphIndex + line->numberOfGlyphs - 1u;
+          }
+        }
+      }
+
       if( 1u == numberOfLaidOutGlyphs )
       {
         // not a point try to do ellipsis with only one laid out character.
@@ -116,55 +158,61 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
         {
           const GlyphInfo& glyphToRemove = *( glyphs + index );
 
-          // Need to reshape the glyph as the font may be different in size.
-          const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphToRemove.fontId ) );
-
-          if( !firstPenSet )
+          if( 0u != glyphToRemove.fontId )
           {
-            const Vector2& position = *( glyphPositions + index );
+            // i.e. The font id of the glyph shaped from the '\n' character is zero.
 
-            // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
-            penY = position.y + glyphToRemove.yBearing;
+            // Need to reshape the glyph as the font may be different in size.
+            const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphToRemove.fontId ) );
 
-            // Calculates the first penX which will be used if rtl text is elided.
-            firstPenX = position.x - glyphToRemove.xBearing;
-            if( firstPenX < -ellipsisGlyph.xBearing )
+            if( !firstPenSet )
             {
-              // Avoids to exceed the bounding box when rtl text is elided.
-              firstPenX = -ellipsisGlyph.xBearing;
-            }
+              const Vector2& position = *( glyphPositions + index );
 
-            removedGlypsWidth = -ellipsisGlyph.xBearing;
+              // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+              penY = position.y + glyphToRemove.yBearing;
 
-            firstPenSet = true;
-          }
+              // Calculates the first penX which will be used if rtl text is elided.
+              firstPenX = position.x - glyphToRemove.xBearing;
+              if( firstPenX < -ellipsisGlyph.xBearing )
+              {
+                // Avoids to exceed the bounding box when rtl text is elided.
+                firstPenX = -ellipsisGlyph.xBearing;
+              }
 
-          removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+              removedGlypsWidth = -ellipsisGlyph.xBearing;
 
-          // Calculate the width of the ellipsis glyph and check if it fits.
-          const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
-          if( ellipsisGlyphWidth < removedGlypsWidth )
-          {
-            GlyphInfo& glyphInfo = *( glyphs + index );
-            Vector2& position = *( glyphPositions + index );
-            position.x -= glyphInfo.xBearing;
-
-            // Replace the glyph by the ellipsis glyph.
-            glyphInfo = ellipsisGlyph;
+              firstPenSet = true;
+            }
 
-            // Change the 'x' and 'y' position of the ellipsis glyph.
+            removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
 
-            if( position.x > firstPenX )
+            // Calculate the width of the ellipsis glyph and check if it fits.
+            const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+            if( ellipsisGlyphWidth < removedGlypsWidth )
             {
-              position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
-            }
+              GlyphInfo& glyphInfo = *( glyphs + index );
+              Vector2& position = *( glyphPositions + index );
+              position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
 
-            position.x += ellipsisGlyph.xBearing;
-            position.y = penY - ellipsisGlyph.yBearing;
+              // Replace the glyph by the ellipsis glyph.
+              glyphInfo = ellipsisGlyph;
 
-            inserted = true;
+              // Change the 'x' and 'y' position of the ellipsis glyph.
+
+              if( position.x > firstPenX )
+              {
+                position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+              }
+
+              position.x += ellipsisGlyph.xBearing;
+              position.y = penY - ellipsisGlyph.yBearing;
+
+              inserted = true;
+            }
           }
-          else
+
+          if( !inserted )
           {
             if( index > 0u )
             {
@@ -254,8 +302,8 @@ Length View::GetNumberOfGlyphs() const
   {
     VisualModel& model = *mImpl->mVisualModel;
 
-    Length glyphCount = model.GetNumberOfGlyphs();
-    Length positionCount = model.GetNumberOfGlyphPositions();
+    const Length glyphCount = model.mGlyphs.Count();
+    const Length positionCount = model.mGlyphPositions.Count();
 
     DALI_ASSERT_DEBUG( positionCount <= glyphCount && "Invalid glyph positions in Model" );
 
index 5f36226..a354fdc 100644 (file)
@@ -36,47 +36,6 @@ VisualModelPtr VisualModel::New()
   return VisualModelPtr( new VisualModel() );
 }
 
-void VisualModel::SetGlyphs( const GlyphInfo* glyphs,
-                             const CharacterIndex* characterIndices,
-                             const Length* charactersPerGlyph,
-                             Length numberOfGlyphs )
-{
-  if( 0u == numberOfGlyphs )
-  {
-    mGlyphs.Clear();
-    mGlyphsToCharacters.Clear();
-    mCharactersToGlyph.Clear();
-    mCharactersPerGlyph.Clear();
-    mGlyphsPerCharacter.Clear();
-  }
-  else
-  {
-    if( NULL != glyphs )
-    {
-      mGlyphs.Resize( numberOfGlyphs );
-      memcpy( mGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
-    }
-
-    if( NULL != characterIndices )
-    {
-      mGlyphsToCharacters.Resize( numberOfGlyphs );
-      memcpy( mGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
-    }
-
-    if( NULL != charactersPerGlyph )
-    {
-      mCharactersPerGlyph.Resize( numberOfGlyphs );
-      memcpy( mCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
-
-      // Build the glyphs per character table.
-      CreateGlyphsPerCharacterTable();
-
-      // Build the characters to glyph conversion table.
-      CreateCharacterToGlyphTable();
-    }
-  }
-}
-
 void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters )
 {
   // 1) Reserve some space for the characters to avoid reallocations.
@@ -157,11 +116,6 @@ void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
   }
 }
 
-Length VisualModel::GetNumberOfGlyphs() const
-{
-  return mGlyphs.Count();
-}
-
 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
                              GlyphIndex glyphIndex,
                              Length numberOfGlyphs ) const
@@ -169,81 +123,6 @@ void VisualModel::GetGlyphs( GlyphInfo* glyphs,
   memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
 }
 
-const GlyphInfo& VisualModel::GetGlyphInfo( GlyphIndex glyphIndex ) const
-{
-  return mGlyphs[glyphIndex];
-}
-
-void VisualModel::ReplaceGlyphs( GlyphIndex glyphIndex,
-                                 Length numberOfGlyphsToRemove,
-                                 const GlyphInfo* const glyphs,
-                                 const Length* const numberOfCharacters,
-                                 Length numberOfGlyphsToInsert )
-{
-}
-
-CharacterIndex VisualModel::GetCharacterIndex( GlyphIndex glyphIndex ) const
-{
-  return mGlyphsToCharacters[glyphIndex];
-}
-
-Length VisualModel::GetCharactersPerGlyph( GlyphIndex glyphIndex ) const
-{
-  return mCharactersPerGlyph[glyphIndex];
-}
-
-GlyphIndex VisualModel::GetGlyphIndex( CharacterIndex characterIndex ) const
-{
-  return mCharactersToGlyph[characterIndex];
-}
-
-void VisualModel::GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharacters ) const
-{
-  memcpy( characterToGlyphMap, mCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
-}
-
-void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
-                                          GlyphIndex glyphIndex,
-                                          Length numberOfGlyphs ) const
-{
-  memcpy( glyphToCharacter, mGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
-}
-
-void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
-                                            GlyphIndex glyphIndex,
-                                            Length numberOfGlyphs ) const
-{
-  memcpy( charactersPerGlyph, mCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
-}
-
-void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
-                                            CharacterIndex characterIndex,
-                                            Length numberOfCharacters ) const
-{
-  memcpy( glyphsPerCharacter, mGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
-}
-
-void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
-                                     Length numberOfGlyphs )
-{
-  if( 0u == numberOfGlyphs )
-  {
-    mGlyphPositions.Clear();
-  }
-  else
-  {
-    mGlyphPositions.Resize( numberOfGlyphs );
-    memcpy( mGlyphPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
-  }
-}
-
-Length VisualModel::GetNumberOfGlyphPositions() const
-{
-  return mGlyphPositions.Count();
-}
-
 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
                                      GlyphIndex glyphIndex,
                                      Length numberOfGlyphs ) const
@@ -251,44 +130,6 @@ void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
   memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
 }
 
-const Vector2& VisualModel::GetGlyphPosition( GlyphIndex glyphIndex ) const
-{
-  return *( mGlyphPositions.Begin() + glyphIndex );
-}
-
-void VisualModel::ReplaceGlyphPositions( GlyphIndex glyphIndex,
-                                         Length numberOfGlyphsToRemove,
-                                         const Vector2* const positions,
-                                         Length numberOfGlyphsToInsert )
-{
-}
-
-void VisualModel::SetLines( const LineRun* const lines,
-                            Length numberOfLines )
-{
-  if( 0u == numberOfLines )
-  {
-    mLines.Clear();
-  }
-  else
-  {
-    mLines.Resize( numberOfLines );
-    memcpy( mLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
-  }
-}
-
-Length VisualModel::GetNumberOfLines() const
-{
-  return mLines.Count();
-}
-
-void VisualModel::GetLines( LineRun* lines,
-                            LineIndex lineIndex,
-                            Length numberOfLines ) const
-{
-  memcpy( lines, mLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
-}
-
 void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
                                     Length numberOfGlyphs,
                                     LineIndex& firstLine,
@@ -343,13 +184,6 @@ void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
   memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
 }
 
-LineIndex VisualModel::GetLineOfGlyph( GlyphIndex glyphIndex )
-{
-  const CharacterIndex characterIndex = *( mGlyphsToCharacters.Begin() + glyphIndex );
-
-  return GetLineOfCharacter( characterIndex );
-}
-
 LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
 {
   // 1) Check first in the cached line.
@@ -383,13 +217,6 @@ LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
   return index;
 }
 
-void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
-                                Length numberOfGlyphsToRemove,
-                                const LineRun* const lines,
-                                Length numberOfGlyphsToInsert )
-{
-}
-
 void VisualModel::SetNaturalSize( const Vector2& size  )
 {
   mNaturalSize = size;
index fb9f7bc..f290ba5 100644 (file)
@@ -63,22 +63,6 @@ public:
   // Glyph interface.
 
   /**
-   * @brief Replaces any glyphs previously set.
-   *
-   * @note If the number of glyphs is zero, all buffers are cleared.
-   * @note If one pointer is NULL and the number of glyphs is not zero, the buffer is not touched.
-   *
-   * @param[in] glyphs An array of glyphs in the visual order.
-   * @param[in] characterIndices An array containing the first character in the logical model that each glyph relates to.
-   * @param[in] charactersPerGlyph An array containing the number of characters per glyph.
-   * @param[in] numberOfGlyphs The number of glyphs.
-   */
-  void SetGlyphs( const GlyphInfo* glyphs,
-                  const CharacterIndex* characterIndices,
-                  const Length* charactersPerGlyph,
-                  Length numberOfGlyphs );
-
-  /**
    * @brief Creates the character to glyph conversion table.
    *
    * @pre The glyphs per character table needs to be created first.
@@ -95,13 +79,6 @@ public:
   void CreateGlyphsPerCharacterTable( Length numberOfCharacters = 0u );
 
   /**
-   * @brief Retrieves the number of glyphs.
-   *
-   * @return The number of glyphs.
-   */
-  Length GetNumberOfGlyphs() const;
-
-  /**
    * @brief Retrieves glyphs in the given buffer.
    *
    * The size of the @p glyphs buffer needs to be big enough to copy the @p numberOfGlyphs.
@@ -113,101 +90,9 @@ public:
                   GlyphIndex glyphIndex,
                   Length numberOfGlyphs ) const;
 
-  /**
-   * @brief Retrieves a glyph.
-   *
-   * @param[in] glyphIndex Index to a glyph.
-   *
-   * @return A glyph.
-   */
-  const GlyphInfo& GetGlyphInfo( GlyphIndex glyphIndex ) const;
-
-  /**
-   * @brief Replaces glyphs.
-   *
-   * If the @p numberOfGlyphsToRemove is zero, this operation is like an insert.
-   * If the @p numberOfGlyphsToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] glyphIndex Where to replace the glyphs.
-   * @param[in] numberOfGlyphsToRemove The number of glyphs to be removed.
-   * @param[in] glyphs Pointer to a buffer with the new glyphs.
-   * @param[in] numberOfCharacters Pointer to a buffer with the number of characters per glyph.
-   * @param[in] numberOfGlyphsToInsert The number of new glyphs in the buffer.
-   */
-  void ReplaceGlyphs( GlyphIndex glyphIndex,
-                      Length numberOfGlyphsToRemove,
-                      const GlyphInfo* const glyphs,
-                      const Length* const numberOfCharacters,
-                      Length numberOfGlyphsToInsert );
-
   // Character <--> Glyph conversion
 
   /**
-   * @brief Retrieves the first character in the logical model which a glyph represents.
-   *
-   * @note After shaping several characters may be represented by the same glyph.
-   * Alternatively several glyphs may be required to display a character.
-   * @param[in] glyphIndex The glyph index.
-   * @return The character index.
-   */
-  CharacterIndex GetCharacterIndex( GlyphIndex glyphIndex ) const;
-
-  /**
-   * @brief Query the number of characters the glyph represents.
-   *
-   * @param[in] glyphIndex The glyph index.
-   * @return The number of characters represented by the glyph.
-   */
-  Length GetCharactersPerGlyph( GlyphIndex glyphIndex ) const;
-
-  /**
-   * @brief Retrieves the first glyph in the visual model which represents a given character.
-   *
-   * @note After shaping several characters may be represented by the same glyph.
-   * Alternatively several glyphs may be required to display a character.
-   * @param[in] characterIndex The character index.
-   * @return The glyph index.
-   */
-  GlyphIndex GetGlyphIndex( CharacterIndex characterIndex ) const;
-
-  /**
-   * @brief Retrieves the whole or part of the character to glyph conversion map.
-   *
-   * The size of the buffer needs to be big enough to copy the @p numberOfCharacters.
-   *
-   * @param[out] characterToGlyphMap Pointer to a buffer where the conversion map is copied.
-   * @param[in] characterIndex Index to the first character.
-   * @param[in] numberOfCharacters The number of characters.
-   */
-  void GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
-                               CharacterIndex characterIndex,
-                               Length numberOfCharacters ) const;
-
-  /**
-   * @brief Retrieves the whole or part of the glyph to character conversion map.
-   *
-   * The size of the buffer needs to be big enough to copy the @p numberOfGlyphs.
-   *
-   * @param[out] glyphToCharacter Pointer to a buffer where the conversion map is copied.
-   * @param[in] glyphIndex Index to the first glyph.
-   * @param[in] numberOfGlyphs The number of glyphs.
-   */
-  void GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
-                               GlyphIndex glyphIndex,
-                               Length numberOfGlyphs ) const;
-
-  /**
-   * @brief Retrieves for each glyph the number of characters the glyph represents.
-   *
-   * @param[out] charactersPerGlyph Pointer to a buffer where the number of characters for each glyph are copied.
-   * @param[in] glyphIndex Index to the first glyph.
-   * @param[in] numberOfGlyphs The number of glyphs.
-   */
-  void GetCharactersPerGlyphMap( Length* charactersPerGlyph,
-                                 GlyphIndex glyphIndex,
-                                 Length numberOfGlyphs ) const;
-
-  /**
    * @brief Retrieves for each character the number of glyphs the character is shaped.
    *
    * @param[out] glyphsPerCharacter Pointer to a buffer where the number of glyphs for each character are copied.
@@ -221,25 +106,6 @@ public:
   // Position interface
 
   /**
-   * @brief Replaces any glyph positions previously set.
-   *
-   * @note If the number of glyphs is zero the position buffer is cleared.
-   *
-   * @param[in] glyphPositions An array of visual positions for each glyph.
-   * @param[in] numberOfGlyphs The number of positions.
-   */
-  void SetGlyphPositions( const Vector2* glyphPositions,
-                          Length numberOfGlyphs );
-
-  /**
-   * @brief Retrieves the number of glyph positions set.
-   *
-   * @note This may be less than the number of glyphs in the model.
-   * @return The number of glyphs.
-   */
-  Length GetNumberOfGlyphPositions() const;
-
-  /**
    * @brief Retrieves the glyph positions.
    *
    * @pre The size of the @p positions buffer needs to be big enough to copy the @p numberOfGlyphs positions.
@@ -251,69 +117,9 @@ public:
                           GlyphIndex glyphIndex,
                           Length numberOfGlyphs ) const;
 
-  /**
-   * @brief Retrieve the glyph's position of the given glyph.
-   *
-   * @param[in] glyphIndex Index to the glyph.
-   *
-   * @return The glyph's position.
-   */
-  const Vector2& GetGlyphPosition( GlyphIndex glyphIndex ) const;
-
-  /**
-   * @brief Replaces glyph's positions.
-   *
-   * If the @p numberOfGlyphsToRemove is zero, this operation is like an insert.
-   * If the @p numberOfGlyphsToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] glyphIndex Where to replace the glyph's positions.
-   * @param[in] numberOfGlyphsToRemove The number of glyph's positions to be removed.
-   * @param[in] positions Pointer to a buffer with the new glyph's positions.
-   * @param[in] numberOfGlyphsToInsert The number of new glyph's positions in the buffer.
-   */
-  void ReplaceGlyphPositions( GlyphIndex glyphIndex,
-                              Length numberOfGlyphsToRemove,
-                              const Vector2* const positions,
-                              Length numberOfGlyphsToInsert );
-
   // Line interface.
 
   /**
-   * @brief Sets the lines.
-   *
-   * Replaces any lines previously set.
-   *
-   * Every line is an item run containing the index to the first glyph of the line and the number of glyphs.
-   *
-   * @note If the number of lines is zero or the pointer is NULL, the lines buffer is cleared.
-   *
-   * @param[in] lines Pointer to a buffer containing all the line runs.
-   * @param[in] numberOfLines The number of lines in the buffer.
-   */
-  void SetLines( const LineRun* const lines,
-                 Length numberOfLines );
-
-  /**
-   * @brief Retrieves the number of lines of the whole text.
-   *
-   * @return The number of lines.
-   */
-  Length GetNumberOfLines() const;
-
-  /**
-   * @brief Retrieves lines.
-   *
-   * The size of the @p lines buffer needs to be big enough to copy the @p numberOfLines.
-   *
-   * @param[out] lines Pointer to a buffer where the lines are copied.
-   * @param[in] lineIndex Index to the first line.
-   * @param[in] numberOfLines Number of lines to be copied.
-   */
-  void GetLines( LineRun* lines,
-                 LineIndex lineIndex,
-                 Length numberOfLines ) const;
-
-  /**
    * @brief Retrieves the number of lines and the index to the first line where the given range of glyphs is laid out.
    *
    * @param[in] glyphIndex Index to the first glyph.
@@ -325,6 +131,7 @@ public:
                          Length numberOfGlyphs,
                          LineIndex& firstLine,
                          Length& numberOfLines ) const;
+
   /**
    * @brief Retrieves the lines where the given range of glyphs is laid out.
    *
@@ -339,15 +146,6 @@ public:
                              Length numberOfGlyphs ) const;
 
   /**
-   * @brief Retrieves the line index where the glyph is laid-out.
-   *
-   * @param[in] glyphIndex The glyph's index.
-   *
-   * @return The line index.
-   */
-  LineIndex GetLineOfGlyph( GlyphIndex glyphIndex );
-
-  /**
    * @brief Retrieves the line index where the character is laid-out.
    *
    * @param[in] characterIndex The character's index.
@@ -356,22 +154,6 @@ public:
    */
   LineIndex GetLineOfCharacter( CharacterIndex characterIndex );
 
-  /**
-   * @brief Replaces lines for the given range of glyphs.
-   *
-   * If the @p numberOfGlyphsToRemove is zero, this operation is like an insert.
-   * If the @p numberOfGlyphsToInsert is zero, this operation is like a remove.
-   *
-   * @param[in] glyphIndex Index of the first glyph where to replace the line info.
-   * @param[in] numberOfGlyphsToRemove The number of glyphs to be the line info removed.
-   * @param[in] lines Pointer to a buffer with the lines.
-   * @param[in] numberOfGlyphsToInsert The number of characters to be the line info inserted.
-   */
-  void ReplaceLines( GlyphIndex glyphIndex,
-                     Length numberOfGlyphsToRemove,
-                     const LineRun* const lines,
-                     Length numberOfGlyphsToInsert );
-
   // Size interface
 
   /**
index 7bcaad4..88b588d 100644 (file)
@@ -425,17 +425,12 @@ public:
 
         case Toolkit::Control::Property::BACKGROUND_IMAGE:
         {
-          if ( value.HasKey( "image" ) )
+          Image image = Scripting::NewImage( value );
+          if ( image )
           {
-            Property::Map imageMap = value.GetValue( "image" ).Get< Property::Map >();
-            Image image = Scripting::NewImage( imageMap );
-
-            if ( image )
-            {
-              controlImpl.SetBackgroundImage( image );
-            }
+            controlImpl.SetBackgroundImage( image );
           }
-          else if ( value.Get< Property::Map >().Empty() )
+          else
           {
             // An empty map means the background is no longer required
             controlImpl.ClearBackground();
@@ -499,9 +494,7 @@ public:
             Image image = back->actor.GetRendererAt(0).GetMaterial().GetSamplerAt(0).GetImage();
             if ( image )
             {
-              Property::Map imageMap;
-              Scripting::CreatePropertyMap( image, imageMap );
-              map[ "image" ] = imageMap;
+              Scripting::CreatePropertyMap( image, map );
             }
           }
 
@@ -875,6 +868,9 @@ Control::Control( ControlBehaviour behaviourFlags )
 
 void Control::Initialize()
 {
+  // Call deriving classes so initialised before styling is applied to them.
+  OnInitialize();
+
   if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
   {
     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
@@ -882,7 +878,7 @@ void Control::Initialize()
     // Register for style changes
     styleManager.StyleChangeSignal().Connect( this, &Control::OnStyleChange );
 
-    // SetTheme
+    // Apply the current style
     GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
   }
 
@@ -890,9 +886,6 @@ void Control::Initialize()
   {
     SetKeyboardNavigationSupport( true );
   }
-
-  // Calling deriving classes
-  OnInitialize();
 }
 
 void Control::OnInitialize()
index 0b52ed4..dd109a3 100644 (file)
@@ -597,7 +597,7 @@ private:
  * @param handle
  * @return implementation
  */
-Internal::Control& GetImplementation( Dali::Toolkit::Control& handle );
+DALI_IMPORT_API Internal::Control& GetImplementation( Dali::Toolkit::Control& handle );
 
 /**
  * @brief Get implementation from the handle
@@ -606,7 +606,7 @@ Internal::Control& GetImplementation( Dali::Toolkit::Control& handle );
  * @param handle
  * @return implementation
  */
-const Internal::Control& GetImplementation( const Dali::Toolkit::Control& handle );
+DALI_IMPORT_API const Internal::Control& GetImplementation( const Dali::Toolkit::Control& handle );
 
 } // namespace Internal
 
index a43c874..5bf8561 100644 (file)
@@ -46,6 +46,11 @@ ImageActor CreateSolidColorActor( const Vector4& color, bool border, const Vecto
 
   // Create the image
   PixelBuffer* pixbuf = imageData.GetBuffer();
+  if( !pixbuf )
+  {
+    return image;
+  }
+
   Vector4 outerColor = color;
   if ( border )
   {
index d30f809..5da66a5 100755 (executable)
@@ -66,12 +66,12 @@ public:
   {
     enum
     {
-      SCROLL_DIRECTION = PROPERTY_START_INDEX,        ///< name "scroll-direction",        @see SetScrollDirection(),       type std::string
-      INDICATOR_HEIGHT_POLICY,                        ///< name "indicator-height-policy", @see SetIndicatorHeightPolicy(), type std::string
-      INDICATOR_FIXED_HEIGHT,                         ///< name "indicator-fixed-height",  @see SetIndicatorFixedHeight(),  type float
-      INDICATOR_SHOW_DURATION,                        ///< name "indicator-show-duration", @see SetIndicatorShowDuration(), type float
-      INDICATOR_HIDE_DURATION,                        ///< name "indicator-hide-duration", @see SetIndicatorHideDuration(), type float
-      SCROLL_POSITION_INTERVALS                       ///< name "scroll-position-intervals",                                type float
+      SCROLL_DIRECTION = PROPERTY_START_INDEX, ///< name "scroll-direction",         @see SetScrollDirection(),        type std::string
+      INDICATOR_HEIGHT_POLICY,                 ///< name "indicator-height-policy",  @see SetIndicatorHeightPolicy(),  type std::string
+      INDICATOR_FIXED_HEIGHT,                  ///< name "indicator-fixed-height",   @see SetIndicatorFixedHeight(),   type float
+      INDICATOR_SHOW_DURATION,                 ///< name "indicator-show-duration",  @see SetIndicatorShowDuration(),  type float
+      INDICATOR_HIDE_DURATION,                 ///< name "indicator-hide-duration",  @see SetIndicatorHideDuration(),  type float
+      SCROLL_POSITION_INTERVALS                ///< name "scroll-position-intervals",@see SetScrollPositionIntervals() type Property::Array
     };
   };
 
index 6daa933..12a6baf 100644 (file)
@@ -243,6 +243,11 @@ void ItemView::GetItemsRange(ItemRange& range)
   GetImpl(*this).GetItemsRange(range);
 }
 
+ItemView::LayoutActivatedSignalType& ItemView::LayoutActivatedSignal()
+{
+  return GetImpl(*this).LayoutActivatedSignal();
+}
+
 } // namespace Toolkit
 
 } // namespace Dali
index ca51a44..cb0859d 100644 (file)
@@ -46,7 +46,13 @@ typedef IntrusivePtr<ItemLayout> ItemLayoutPtr;
  *
  * Multiple ItemLayouts may be provided, to determine the logical position of each item a layout.
  * Actors are provided from an external ItemFactory, to display the currently visible items.
+ *
+ * Signals
+ * | %Signal Name                     | Method                                     |
+ * |----------------------------------|--------------------------------------------|
+ * | layout-activated                 | @ref LayoutActivatedSignal()               |
  */
+
 class DALI_IMPORT_API ItemView : public Scrollable
 {
 public:
@@ -73,6 +79,10 @@ public:
     };
   };
 
+  // Signals
+
+  typedef Signal< void () > LayoutActivatedSignalType;
+
 public:
 
   /**
@@ -421,6 +431,20 @@ public:
    */
   void GetItemsRange(ItemRange& range);
 
+public: // Signals
+
+  /**
+   * @brief Signal emitted when layout activation is finished.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName();
+   * @endcode
+   * @pre The Object has been initialized.
+   * @return The signal to connect to.
+   */
+  ItemView::LayoutActivatedSignalType& LayoutActivatedSignal();
+
 public: // Not intended for application developers
 
   /**
index c92f36e..126c254 100644 (file)
@@ -29,10 +29,6 @@ namespace Dali
 namespace Toolkit
 {
 
-const std::string TableView::CELL_INDICES_PROPERTY_NAME("cell-indices");
-const std::string TableView::ROW_SPAN_PROPERTY_NAME("row-span");
-const std::string TableView::COLUMN_SPAN_PROPERTY_NAME("column-span");
-
 TableView::TableView()
 {
 }
@@ -137,22 +133,22 @@ Size TableView::GetCellPadding()
 
 void TableView::SetFitHeight( unsigned int rowIndex )
 {
-  GetImpl(*this).SetRowPolicy( rowIndex, Internal::TableView::FIT );
+  GetImpl(*this).SetFitHeight( rowIndex );
 }
 
 bool TableView::IsFitHeight( unsigned int rowIndex ) const
 {
-  return ( GetImpl(*this).GetRowPolicy( rowIndex ) == Internal::TableView::FIT );
+  return GetImpl(*this).IsFitHeight( rowIndex );
 }
 
 void TableView::SetFitWidth( unsigned int columnIndex )
 {
-  GetImpl(*this).SetColumnPolicy( columnIndex, Internal::TableView::FIT );
+  GetImpl(*this).SetFitWidth( columnIndex );
 }
 
 bool TableView::IsFitWidth( unsigned int columnIndex ) const
 {
-  return ( GetImpl(*this).GetColumnPolicy( columnIndex ) == Internal::TableView::FIT );
+  return GetImpl(*this).IsFitWidth( columnIndex );
 }
 
 void TableView::SetFixedHeight( unsigned int rowIndex, float height )
index 46e3437..fb59939 100644 (file)
@@ -41,6 +41,38 @@ class TableView;
  * TableView constrains the x and y position and width and height of the child actors.
  * z position and depth are left intact so that 3D model actors can also be laid out
  * in a grid without loosing their depth scaling.
+ *
+ * @nosubgrouping
+ *
+ * Per-child Custom properties for script supporting.
+ *
+ * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild,
+ * the following custom properties of the actor are checked to decide the actor position inside the table
+ *
+ * These properties are registered dynamically to the child and is non-animatable.
+ *
+ * | %Property Name            | Type               |
+ * |---------------------------|--------------------|
+ * | cell-index                | Vector2            |
+ * | row-span                  | float              | // type float (Currently builder is unable to differentiate integer and float from Json string)
+ * | column-span               | float              | // type float (Currently builder is unable to differentiate integer and float from Json string)
+ * | cell-horizontal-alignment | string             | // available values: left, center, right
+ * | cell-vertical-alignment   | string             | // available values: top, center, bottom
+ *
+ * @code
+ * "name":"gallery-1",
+ * "type":"ImageActor",
+ * "image": {
+ *    "filename": "{DALI_IMAGE_DIR}gallery-small-1.jpg"
+ *  },
+ *  "custom-properties": {
+ *     "cell-index":[1,1],  // property to specify the top-left cell this child occupies, if not set, the first available cell is used
+ *     "row-span":3,        // property to specify how many rows this child occupies, if not set, default value is 1
+ *     "column-span": 2,    // property to specify how many columns this child occupies, if nor set, default value is 1
+ *     "cell-horizontal-alignment": "left", // property to specify how to align horizontally inside the cells, if not set, default value is 'left'
+ *     "cell-vertical-alignment": "center"  // property to specify how to align vertically inside the cells, if not set, default value is 'top'
+ *   }
+ * @endcode
  */
 class DALI_IMPORT_API TableView : public Control
 {
@@ -64,7 +96,8 @@ public:
    * "layout-rows":
       {
         "0": { "policy": "fixed", "value": 40 },       //@see SetFixedHight
-        "2": { "policy": "relative", "value": 0.33 }   //@see SetRelativeHeight
+        "2": { "policy": "relative", "value": 0.33 },  //@see SetRelativeHeight
+        "3": { "policy": "fit", "value":0.0 }          //@see SetFitHeight, the value is not used, its height is decided by the children in this row
       }
    * @endcode
    *
@@ -74,6 +107,7 @@ public:
    * "layout-columns":
       {
         "0": { "policy": "fixed", "value": 40 },       //@see SetFixedWidth
+        "1": { "policy": "fit", "value":0.0 }          //@see SetFitHeight, the value is not used, its width is decided by the children in this column
         "2": { "policy": "relative", "value": 0.33 }   //@see SetRelativeWidth
       }
    * @endcode
@@ -90,11 +124,6 @@ public:
     };
   };
 
-  // Custom properties for where to put the actor, these properties should be registered to the child which would be added to the table
-  static const std::string CELL_INDICES_PROPERTY_NAME;           ///< Property, name "cell-indices", type Vector2
-  static const std::string ROW_SPAN_PROPERTY_NAME;               ///< Property, name "row-span",     type float (Currently builder is unable to differentiate integer and float from Json string)
-  static const std::string COLUMN_SPAN_PROPERTY_NAME;            ///< Property, name "column-span",  type float (Currently builder is unable to differentiate integer and float from Json string)
-
   /**
    * @brief Describes how the size of a row / column been set
    */
@@ -102,7 +131,8 @@ public:
   {
     FIXED,      ///< Fixed with the given value.
     RELATIVE,   ///< Calculated as percentage of the remainder after subtracting Padding and Fixed height/width
-    FILL        ///< Get the remainder of the 100% (after subtracting Padding, Fixed and Relative height/ width) divided evenly between 'fill' rows/columns
+    FILL,       ///< Default policy, get the remainder of the 100% (after subtracting Padding, Fixed and Relative height/ width) divided evenly between 'fill' rows/columns
+    FIT         ///< Fit around its children.
   };
 
   /**
@@ -382,11 +412,13 @@ public:
   unsigned int GetColumns();
 
   /**
-   * @brief Set the alignment on a cell
+   * @brief Set the alignment on a cell.
+   *
+   * Cells without calling this function have the default values of LEFT and TOP respectively.
    *
-   * @param[in] position The cell to set alignment on
-   * @param[in] horizontal The horizontal alignment
-   * @param[in] vertical The vertical alignment
+   * @param[in] position The cell to set alignment on.
+   * @param[in] horizontal The horizontal alignment.
+   * @param[in] vertical The vertical alignment.
    */
   void SetCellAlignment( CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical );
 
index 59e5a69..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 = 43;
+const unsigned int TOOLKIT_MICRO_VERSION = 46;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index f850715..fcfae07 100644 (file)
@@ -37,6 +37,12 @@ distributing this software or its derivatives.
       "font-style":"Regular",
       "point-size":18
     },
+    "textselectionpopup":
+    {
+      "popup-max-size":[400,100],
+      "popup-min-size":[100,65],
+      "background-color":[0.0,0.0,0.0,1.0]
+    },
     "textfield":
     {
       "font-family":"HelveticaNeue",
index 8deaa50..7c4099e 100644 (file)
@@ -84,7 +84,12 @@ distributing this software or its derivatives.
     {
       "point-size":10
     },
-
+    "textselectionpopup":
+    {
+      "popup-max-size":[400,100],
+      "popup-min-size":[100,65],
+      "background-color":[0.0,0.0,0.0,1.0]
+    },
     "scrollview":
     {
       "overshoot-effect-color":"B018"
index de3867f..c804f61 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.0.43
+Version:    1.0.46
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0
index b5595f8..c58d991 100644 (file)
@@ -769,7 +769,6 @@ Dali::Property::Value PropertyValueWrapper::ExtractPropertyValue( v8::Isolate* i
       break;
     }
     case Dali::Property::NONE:
-    case Dali::Property::TYPE_COUNT:
     default:
     {
       break;