[dali_1.1.6] Merge branch 'devel/master' 35/49235/1
authorTom Robinson <tom.robinson@samsung.com>
Fri, 9 Oct 2015 09:49:17 +0000 (10:49 +0100)
committerTom Robinson <tom.robinson@samsung.com>
Fri, 9 Oct 2015 09:49:17 +0000 (10:49 +0100)
Change-Id: I1d00c300da2b1b3fd986f4752a7a4d8531ffb576

107 files changed:
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/controls/renderer-factory/control-renderer.h
dali-toolkit/images-common/00_popup_bg.9.png [moved from dali-toolkit/images/00_popup_bg.9.png with 100% similarity]
dali-toolkit/images-common/00_popup_bg.png [moved from dali-toolkit/images/00_popup_bg.png with 100% similarity]
dali-toolkit/images-common/00_popup_bottom_bg.png [moved from dali-toolkit/images/00_popup_bottom_bg.png with 100% similarity]
dali-toolkit/images-common/00_popup_bubble_bg.png [moved from dali-toolkit/images/00_popup_bubble_bg.png with 100% similarity]
dali-toolkit/images-common/00_popup_bubble_tail_bottom.png [moved from dali-toolkit/images/00_popup_bubble_tail_bottom.png with 100% similarity]
dali-toolkit/images-common/00_popup_button_bg.png [moved from dali-toolkit/images/00_popup_button_bg.png with 100% similarity]
dali-toolkit/images-common/00_popup_button_pressed.png [moved from dali-toolkit/images/00_popup_button_pressed.png with 100% similarity]
dali-toolkit/images-common/B16-8_TTS_focus.png [moved from dali-toolkit/images/B16-8_TTS_focus.png with 100% similarity]
dali-toolkit/images-common/button-disabled.9.png [moved from dali-toolkit/images/button-disabled.9.png with 100% similarity]
dali-toolkit/images-common/button-down-disabled.9.png [moved from dali-toolkit/images/button-down-disabled.9.png with 100% similarity]
dali-toolkit/images-common/button-down.9.png [moved from dali-toolkit/images/button-down.9.png with 100% similarity]
dali-toolkit/images-common/button-up.9.png [moved from dali-toolkit/images/button-up.9.png with 100% similarity]
dali-toolkit/images-common/checkbox-selected-diabled.png [moved from dali-toolkit/images/checkbox-selected-diabled.png with 100% similarity]
dali-toolkit/images-common/checkbox-selected.png [moved from dali-toolkit/images/checkbox-selected.png with 100% similarity]
dali-toolkit/images-common/checkbox-unselected-disabled.png [moved from dali-toolkit/images/checkbox-unselected-disabled.png with 100% similarity]
dali-toolkit/images-common/checkbox-unselected.png [moved from dali-toolkit/images/checkbox-unselected.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_clipboard.png [moved from dali-toolkit/images/copy_paste_icon_clipboard.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_copy.png [moved from dali-toolkit/images/copy_paste_icon_copy.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_cut.png [moved from dali-toolkit/images/copy_paste_icon_cut.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_paste.png [moved from dali-toolkit/images/copy_paste_icon_paste.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_select.png [moved from dali-toolkit/images/copy_paste_icon_select.png with 100% similarity]
dali-toolkit/images-common/copy_paste_icon_select_all.png [moved from dali-toolkit/images/copy_paste_icon_select_all.png with 100% similarity]
dali-toolkit/images-common/cursor_handler_ball_center.png [moved from dali-toolkit/images/cursor_handler_center.png with 100% similarity]
dali-toolkit/images-common/file.list [moved from dali-toolkit/images/file.list with 100% similarity]
dali-toolkit/images-common/insertpoint-icon-pressed.png [moved from dali-toolkit/images/insertpoint-icon-pressed.png with 100% similarity]
dali-toolkit/images-common/insertpoint-icon.png [moved from dali-toolkit/images/insertpoint-icon.png with 100% similarity]
dali-toolkit/images-common/keyboard_focus.png [moved from dali-toolkit/images/keyboard_focus.png with 100% similarity]
dali-toolkit/images-common/magnifier.png [moved from dali-toolkit/images/magnifier.png with 100% similarity]
dali-toolkit/images-common/popup_bg.png [moved from dali-toolkit/images/popup_bg.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_bg.#.png [moved from dali-toolkit/images/popup_bubble_bg.#.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_bg_ef.#.png [moved from dali-toolkit/images/popup_bubble_bg_ef.#.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_bg_line.#.png [moved from dali-toolkit/images/popup_bubble_bg_line.#.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_bottom.png [moved from dali-toolkit/images/popup_bubble_tail_bottom.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_bottom_ef.png [moved from dali-toolkit/images/popup_bubble_tail_bottom_ef.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_bottom_line.png [moved from dali-toolkit/images/popup_bubble_tail_bottom_line.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_top.png [moved from dali-toolkit/images/popup_bubble_tail_top.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_top_ef.png [moved from dali-toolkit/images/popup_bubble_tail_top_ef.png with 100% similarity]
dali-toolkit/images-common/popup_bubble_tail_top_line.png [moved from dali-toolkit/images/popup_bubble_tail_top_line.png with 100% similarity]
dali-toolkit/images-common/popup_scroll.png [moved from dali-toolkit/images/popup_scroll.png with 100% similarity]
dali-toolkit/images-common/popup_tail_down.png [moved from dali-toolkit/images/popup_tail_down.png with 100% similarity]
dali-toolkit/images-common/popup_tail_left.png [moved from dali-toolkit/images/popup_tail_left.png with 100% similarity]
dali-toolkit/images-common/popup_tail_right.png [moved from dali-toolkit/images/popup_tail_right.png with 100% similarity]
dali-toolkit/images-common/popup_tail_up.png [moved from dali-toolkit/images/popup_tail_up.png with 100% similarity]
dali-toolkit/images-common/radio-button-selected-disabled.png [moved from dali-toolkit/images/radio-button-selected-disabled.png with 100% similarity]
dali-toolkit/images-common/radio-button-selected.png [moved from dali-toolkit/images/radio-button-selected.png with 100% similarity]
dali-toolkit/images-common/radio-button-unselected-disabled.png [moved from dali-toolkit/images/radio-button-unselected-disabled.png with 100% similarity]
dali-toolkit/images-common/radio-button-unselected.png [moved from dali-toolkit/images/radio-button-unselected.png with 100% similarity]
dali-toolkit/images-common/selection-popup-bg.9.png [moved from dali-toolkit/images/selection-popup-bg.9.png with 100% similarity]
dali-toolkit/images-common/selection_handle_ball_left.png [moved from dali-toolkit/images/selection_handle_left.png with 100% similarity]
dali-toolkit/images-common/selection_handle_ball_right.png [moved from dali-toolkit/images/selection_handle_right.png with 100% similarity]
dali-toolkit/images-common/selection_marker_left.png [moved from dali-toolkit/images/selection_marker_left.png with 100% similarity]
dali-toolkit/images-common/selection_marker_right.png [moved from dali-toolkit/images/selection_marker_right.png with 100% similarity]
dali-toolkit/images-common/slider-popup-arrow.png [moved from dali-toolkit/images/slider-popup-arrow.png with 100% similarity]
dali-toolkit/images-common/slider-popup.9.png [moved from dali-toolkit/images/slider-popup.9.png with 100% similarity]
dali-toolkit/images-common/slider-popup.png [moved from dali-toolkit/images/slider-popup.png with 100% similarity]
dali-toolkit/images-common/slider-skin-handle.png [moved from dali-toolkit/images/slider-skin-handle.png with 100% similarity]
dali-toolkit/images-common/slider-skin-progress.9.png [moved from dali-toolkit/images/slider-skin-progress.9.png with 100% similarity]
dali-toolkit/images-common/slider-skin-progress.png [moved from dali-toolkit/images/slider-skin-progress.png with 100% similarity]
dali-toolkit/images-common/slider-skin.9.png [moved from dali-toolkit/images/slider-skin.9.png with 100% similarity]
dali-toolkit/images-common/slider-skin.png [moved from dali-toolkit/images/slider-skin.png with 100% similarity]
dali-toolkit/images-common/text-input-selection-handle-left-press.png [moved from dali-toolkit/images/text-input-selection-handle-left-press.png with 100% similarity]
dali-toolkit/images-common/text-input-selection-handle-left.png [moved from dali-toolkit/images/text-input-selection-handle-left.png with 100% similarity]
dali-toolkit/images-common/text-input-selection-handle-right-press.png [moved from dali-toolkit/images/text-input-selection-handle-right-press.png with 100% similarity]
dali-toolkit/images-common/text-input-selection-handle-right.png [moved from dali-toolkit/images/text-input-selection-handle-right.png with 100% similarity]
dali-toolkit/internal/builder/builder-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/renderers/border/border-renderer.cpp
dali-toolkit/internal/controls/renderers/border/border-renderer.h
dali-toolkit/internal/controls/renderers/color/color-renderer.cpp
dali-toolkit/internal/controls/renderers/color/color-renderer.h
dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h
dali-toolkit/internal/controls/renderers/control-renderer-impl.cpp
dali-toolkit/internal/controls/renderers/control-renderer-impl.h
dali-toolkit/internal/controls/renderers/gradient/gradient-renderer.cpp
dali-toolkit/internal/controls/renderers/gradient/gradient-renderer.h
dali-toolkit/internal/controls/renderers/image/image-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.h
dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp
dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.h
dali-toolkit/internal/controls/renderers/renderer-factory-cache.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-cache.h
dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.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/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json
dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/480x800/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/480x800/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json
dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/file.list
docs/content/main.md
docs/content/programming-guide/styling.h [new file with mode: 0644]
packaging/dali-toolkit.spec

index 521c191..ef8f86d 100644 (file)
@@ -705,8 +705,8 @@ int utcDaliTextFieldEvent02(void)
   // 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 ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 1.f, 25.0f ) ) );
 
   // Render and notify
   application.SendNotification();
@@ -718,8 +718,8 @@ int utcDaliTextFieldEvent02(void)
   DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2.
 
   // Tap away from the start position.
-  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 13.f, 25.0f ) ) );
-  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 13.0f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Possible, 1u, 1u, Vector2( 16.f, 25.0f ) ) );
+  application.ProcessEvent( GenerateTap( Gesture::Started, 1u, 1u, Vector2( 16.0f, 25.0f ) ) );
 
   // Render and notify
   application.SendNotification();
@@ -738,7 +738,12 @@ int utcDaliTextFieldEvent02(void)
   application.SendNotification();
   application.Render();
 
-  // Should not be renderer.
+  // Cursor position should be the same than position2.
+  Vector3 position6 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position2, position6, TEST_LOCATION );// Should be in the same position2.
+
+  // Should not be a renderer.
   DALI_TEST_EQUALS( offscreenRoot.GetChildCount(), 1u, TEST_LOCATION ); // The camera actor only.
 
   END_TEST;
index 75d8ca4..d44e4b4 100644 (file)
 
 # Build the Dali Toolkit library
 
-toolkit_images_dir = ../../../dali-toolkit/images
+toolkit_images_dir = ../../../dali-toolkit/images-common
 toolkit_sounds_dir = ../../../dali-toolkit/sounds
 toolkit_src_dir    = ../../../dali-toolkit/internal
 public_api_src_dir = ../../../dali-toolkit/public-api
 devel_api_src_dir  = ../../../dali-toolkit/devel-api
 
 toolkit_styles_dir = $(STYLE_DIR)
+toolkit_style_images_dir = $(STYLE_DIR)/images
 
-include ../../../dali-toolkit/images/file.list
+include ../../../dali-toolkit/images-common/file.list
 include ../../../dali-toolkit/sounds/file.list
 include ../../../dali-toolkit/styles/file.list
 include ../../../dali-toolkit/internal/file.list
@@ -52,12 +53,16 @@ libdali_toolkit_la_SOURCES = \
 dalistyledir = ${dataReadOnlyDir}/toolkit/styles/
 dalistyle_DATA = ${dali_toolkit_style_files}
 
+dalistyleimagesdir = ${dataReadOnlyDir}/toolkit/styles/images/
+dalistyleimages_DATA = ${dali_toolkit_style_images}
+
 libdali_toolkit_la_DEPENDENCIES =
 
 libdali_toolkit_la_CXXFLAGS = -DDALI_COMPILATION \
                       -DDALI_IMAGE_DIR="\"${daliimagedir}\"" \
                       -DDALI_SOUND_DIR="\"${dalisounddir}\"" \
                       -DDALI_STYLE_DIR="\"${dalistyledir}\"" \
+                      -DDALI_STYLE_IMAGE_DIR="\"${dalistyleimagesdir}\"" \
                       -DDALI_DATA_READ_ONLY_DIR="\"${dataReadOnlyDir}\"" \
                       -Werror -Wall \
                       -I../../../ \
index fe26fab..e95d906 100644 (file)
@@ -116,6 +116,7 @@ public:
    * This function should be called when the control put on stage.
    *
    * @param[in] actor The actor applying this renderer.
+   * @post SetOffStage should be called with the same actor when the control is put off stage otherwise memory will be leaked
    */
   void SetOnStage( Actor& actor );
 
index 4ea4aee..11b92f6 100644 (file)
@@ -1363,6 +1363,7 @@ Builder::Builder()
   defaultDirs[ TOKEN_STRING(DALI_IMAGE_DIR) ]  = DALI_IMAGE_DIR;
   defaultDirs[ TOKEN_STRING(DALI_SOUND_DIR) ]  = DALI_SOUND_DIR;
   defaultDirs[ TOKEN_STRING(DALI_STYLE_DIR) ] = DALI_STYLE_DIR;
+  defaultDirs[ TOKEN_STRING(DALI_STYLE_IMAGE_DIR) ] = DALI_STYLE_IMAGE_DIR;
 
   AddConstants( defaultDirs );
 }
index 554469b..9f7294b 100644 (file)
@@ -222,6 +222,16 @@ void ImageView::OnStageConnection( int depth )
   }
 }
 
+void ImageView::OnStageDisconnection()
+{
+  if( mRenderer )
+  {
+    CustomActor self = Self();
+    mRenderer.SetOffStage( self );
+  }
+}
+
+
 ///////////////////////////////////////////////////////////
 //
 // Properties
index 3af21ce..92c7f70 100644 (file)
@@ -102,6 +102,11 @@ private: // From Control
   virtual void OnStageConnection( int depth );
 
   /**
+   * @copydoc Toolkit::Control::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+  /**
    * @copydoc Toolkit::Control::GetNaturalSize
    */
   virtual Vector3 GetNaturalSize();
index 6542a2c..ad46c2f 100644 (file)
@@ -75,8 +75,8 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
 );
 }
 
-BorderRenderer::BorderRenderer()
-: ControlRenderer(),
+BorderRenderer::BorderRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
   mBorderColor( Color::TRANSPARENT ),
   mBorderSize( 0.f ),
   mBorderColorIndex( Property::INVALID_INDEX ),
@@ -88,10 +88,8 @@ BorderRenderer::~BorderRenderer()
 {
 }
 
-void BorderRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void BorderRenderer::DoInitialize( const Property::Map& propertyMap )
 {
-  Initialize( factoryCache );
-
   Property::Value* color = propertyMap.Find( COLOR_NAME );
   if( !( color && color->Get(mBorderColor) ) )
   {
@@ -130,20 +128,35 @@ void BorderRenderer::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( SIZE_NAME, mBorderSize );
 }
 
-void BorderRenderer::Initialize( RendererFactoryCache& factoryCache)
+void BorderRenderer::InitializeRenderer( Renderer& renderer )
 {
-  mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::BORDER_GEOMETRY );
-  if( !(mImpl->mGeometry) )
+  Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::BORDER_GEOMETRY );
+  if( !geometry )
+  {
+    geometry =  CreateBorderGeometry();
+    mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
+  }
+
+  Shader shader = mFactoryCache.GetShader( RendererFactoryCache::BORDER_SHADER );
+  if( !shader )
   {
-    mImpl->mGeometry =  CreateBorderGeometry();
-    factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    mFactoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, shader );
   }
 
-  mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::BORDER_SHADER );
-  if( !(mImpl->mShader) )
+  if( !renderer )
   {
-    mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    factoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, mImpl->mShader );
+    Material material = Material::New( shader );
+    renderer = Renderer::New( geometry, material );
+  }
+  else
+  {
+    mImpl->mRenderer.SetGeometry( geometry );
+    Material material = mImpl->mRenderer.GetMaterial();
+    if( material )
+    {
+      material.SetShader( shader );
+    }
   }
 }
 
@@ -180,11 +193,11 @@ void BorderRenderer::SetBorderSize( float size )
  * | /| /| /|
  * |/ |/ |/ |
  * 4--5--6--7
- * | /|  | /|
- * |/ |  |/ |
+ * |\ |  |\ |
+ * | \|  | \|
  * 8--9--10-11
- * | /| /| /|
- * |/ |/ ||
+ * | /| /||
+ * |/ |/ | \|
  * 12-13-14-15
  */
 Geometry BorderRenderer::CreateBorderGeometry()
@@ -222,19 +235,17 @@ Geometry BorderRenderer::CreateBorderGeometry()
   borderVertices.SetData(borderVertexData);
 
   // Create indices
-  unsigned int indexData[48] = { 0, 4, 1, 1, 4, 5, 1, 5, 2, 2, 5, 6, 2, 6,3, 3, 6, 7,
-                                 4, 8, 5, 5, 8, 9, 6, 10, 7, 7, 10, 11,
-                                 8, 12, 9, 9, 12, 13, 9, 13, 10, 10, 13, 14, 10, 11, 14, 11, 14, 15};
-
+  unsigned int indexData[24] = { 0,4,1,5,2,6,3,7,7,6,11,10,15,14,14,10,13,9,12,8,8,9,4,5 };
   Property::Map indexFormat;
   indexFormat[INDEX_NAME] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat, 48 );
+  PropertyBuffer indices = PropertyBuffer::New( indexFormat, 24 );
   indices.SetData(indexData);
 
   // Create the geometry object
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( borderVertices );
   geometry.SetIndexBuffer( indices );
+  geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
 
   return geometry;
 }
index 9c53935..859cf01 100644 (file)
@@ -49,8 +49,10 @@ public:
 
   /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  BorderRenderer();
+  BorderRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -60,16 +62,22 @@ public:
 public:  // from ControlRenderer
 
   /**
+   * @copydoc ControlRenderer::SetClipRect
+   */
+  virtual void SetClipRect( const Rect<int>& clipRect );
+
+protected:
+
+  /**
    * @copydoc ControlRenderer::DoInitialize
    */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+  virtual void DoInitialize( const Property::Map& propertyMap );
 
   /**
-   * @copydoc ControlRenderer::SetClipRect
+   * @copydoc ControlRenderer::InitializeRenderer
    */
-  virtual void SetClipRect( const Rect<int>& clipRect );
+  virtual void InitializeRenderer( Renderer& renderer );
 
-protected:
   /**
    * @copydoc ControlRenderer::DoSetOnStage
    */
@@ -83,13 +91,6 @@ protected:
 public:
 
   /**
-   * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
-   *
-   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
-   */
-  void Initialize( RendererFactoryCache& factoryCache );
-
-  /**
    * Set the color of the border.
    * @param[in] color The border color.
    */
index 68164ea..4ca785d 100644 (file)
@@ -67,8 +67,8 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
 );
 }
 
-ColorRenderer::ColorRenderer()
-: ControlRenderer(),
+ColorRenderer::ColorRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
   mBlendColorIndex( Property::INVALID_INDEX )
 {
 }
@@ -77,10 +77,8 @@ ColorRenderer::~ColorRenderer()
 {
 }
 
-void ColorRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ColorRenderer::DoInitialize( const Property::Map& propertyMap )
 {
-  Initialize( factoryCache );
-
   Property::Value* color = propertyMap.Find( COLOR_NAME );
   if( !( color && color->Get(mBlendColor) ) )
   {
@@ -114,29 +112,41 @@ void ColorRenderer::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( COLOR_NAME, mBlendColor );
 }
 
-void ColorRenderer::DoSetOnStage( Actor& actor )
+void ColorRenderer::InitializeRenderer( Renderer& renderer )
 {
-  mBlendColorIndex = (mImpl->mRenderer).RegisterProperty( COLOR_UNIFORM_NAME, mBlendColor );
-  if( mBlendColor.a < 1.f )
+  Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
+  if( !geometry )
   {
-    (mImpl->mRenderer).GetMaterial().SetBlendMode( BlendingMode::ON );
+    geometry =  RendererFactoryCache::CreateQuadGeometry();
+    mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
   }
-}
 
-void ColorRenderer::Initialize( RendererFactoryCache& factoryCache)
-{
-  mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
-  if( !(mImpl->mGeometry) )
+  Shader shader = mFactoryCache.GetShader( RendererFactoryCache::COLOR_SHADER );
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    mFactoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, shader );
+  }
+
+  if( !renderer )
+  {
+    Material material = Material::New( shader );
+    renderer = Renderer::New( geometry, material );
+  }
+  else
   {
-    mImpl->mGeometry =  RendererFactoryCache::CreateQuadGeometry();
-    factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+    mImpl->mRenderer.SetGeometry( geometry );
+    Material material = mImpl->mRenderer.GetMaterial();
+    if( material )
+    {
+      material.SetShader( shader );
+    }
   }
 
-  mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::COLOR_SHADER );
-  if( !(mImpl->mShader) )
+  mBlendColorIndex = renderer.RegisterProperty( COLOR_UNIFORM_NAME, mBlendColor );
+  if( mBlendColor.a < 1.f )
   {
-    mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-    factoryCache.SaveShader( RendererFactoryCache::COLOR_SHADER, mImpl->mShader );
+    renderer.GetMaterial().SetBlendMode( BlendingMode::ON );
   }
 }
 
index ae5ccca..82071b5 100644 (file)
@@ -45,8 +45,10 @@ public:
 
   /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  ColorRenderer();
+  ColorRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -56,11 +58,6 @@ public:
 public:  // from ControlRenderer
 
   /**
-   * @copydoc ControlRenderer::DoInitialize
-   */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
-  /**
    * @copydoc ControlRenderer::SetSize
    */
   virtual void SetSize( const Vector2& size );
@@ -81,19 +78,18 @@ public:  // from ControlRenderer
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
 protected:
+
   /**
-   * @copydoc ControlRenderer::DoSetOnStage
+   * @copydoc ControlRenderer::DoInitialize
    */
-  virtual void DoSetOnStage( Actor& actor );
-
-public:
+  virtual void DoInitialize( const Property::Map& propertyMap );
 
   /**
-   * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
-   *
-   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+   * @copydoc ControlRenderer::InitializeRenderer
    */
-  void Initialize( RendererFactoryCache& factoryCache );
+  virtual void InitializeRenderer( Renderer& renderer );
+
+public:
 
   /**
    * Set the color for rendering.
index 47095c9..c080be2 100644 (file)
@@ -47,8 +47,8 @@ struct Internal::ControlRenderer::Impl
     void CreatePropertyMap( Property::Map& map ) const;
   };
 
-  Geometry mGeometry;
-  Shader   mShader;
+  std::string mCachedRendererKey;  ///< The key to use for caching of the renderer. If it is empty then no caching will occur
+  RendererFactoryCache::CachedRendererPtr mCachedRenderer; ///< The current cached renderer from the Factory Cache. mCachedRenderer == null whilst this control render is offstage
   Renderer mRenderer;
 
   CustomShader* mCustomShader;
index 91343a4..18374e1 100644 (file)
@@ -45,8 +45,9 @@ namespace Toolkit
 namespace Internal
 {
 
-ControlRenderer::ControlRenderer()
-: mImpl( new Impl() )
+ControlRenderer::ControlRenderer( RendererFactoryCache& factoryCache )
+: mImpl( new Impl() ),
+  mFactoryCache( factoryCache )
 {
 }
 
@@ -55,7 +56,7 @@ ControlRenderer::~ControlRenderer()
   delete mImpl;
 }
 
-void ControlRenderer::Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ControlRenderer::Initialize( const Property::Map& propertyMap )
 {
   if( mImpl->mCustomShader )
   {
@@ -73,7 +74,12 @@ void ControlRenderer::Initialize( RendererFactoryCache& factoryCache, const Prop
       }
     }
   }
-  DoInitialize( factoryCache, propertyMap );
+  DoInitialize( propertyMap );
+
+  if( mImpl->mIsOnStage )
+  {
+    InitializeRenderer( mImpl->mRenderer );
+  }
 }
 
 void ControlRenderer::SetSize( const Vector2& size )
@@ -115,10 +121,57 @@ float ControlRenderer::GetDepthIndex() const
   return mImpl->mDepthIndex;
 }
 
+void ControlRenderer::SetCachedRendererKey( const std::string& cachedRendererKey )
+{
+  if( mImpl->mCachedRendererKey == cachedRendererKey )
+  {
+    return;
+  }
+  if( !mImpl->mIsOnStage )
+  {
+    mImpl->mCachedRendererKey = cachedRendererKey;
+  }
+  else
+  {
+    //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
+    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
+    {
+      mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
+    }
+    mImpl->mCachedRenderer.Reset();
+
+    //add the new renderer
+    mImpl->mCachedRendererKey = cachedRendererKey;
+    if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
+    {
+      DALI_ASSERT_DEBUG( mImpl->mRenderer && "The control render is on stage but it doesn't have a valid renderer.");
+      mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
+    }
+  }
+}
+
 void ControlRenderer::SetOnStage( Actor& actor )
 {
-  Material material = Material::New( mImpl->mShader );
-  mImpl->mRenderer = Renderer::New( mImpl->mGeometry, material );
+  if( !mImpl->mCachedRendererKey.empty() && !mImpl->mCustomShader )
+  {
+    mImpl->mCachedRenderer = mFactoryCache.GetRenderer( mImpl->mCachedRendererKey );
+    if( !mImpl->mCachedRenderer || !mImpl->mCachedRenderer->mRenderer )
+    {
+      InitializeRenderer( mImpl->mRenderer );
+      mImpl->mCachedRenderer = mFactoryCache.SaveRenderer( mImpl->mCachedRendererKey, mImpl->mRenderer );
+    }
+
+    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->mRenderer )
+    {
+      mImpl->mRenderer = mImpl->mCachedRenderer->mRenderer;
+    }
+  }
+
+  if( !mImpl->mRenderer )
+  {
+    InitializeRenderer( mImpl->mRenderer );
+  }
+
   mImpl->mRenderer.SetDepthIndex( mImpl->mDepthIndex );
   actor.AddRenderer( mImpl->mRenderer );
   mImpl->mIsOnStage = true;
@@ -132,6 +185,13 @@ void ControlRenderer::SetOffStage( Actor& actor )
   {
     DoSetOffStage( actor );
 
+    //remove the cached renderer from the cache if we and the cache are the only things that hold a reference to it
+    if( mImpl->mCachedRenderer && mImpl->mCachedRenderer->ReferenceCount() == 2 )
+    {
+      mFactoryCache.RemoveRenderer( mImpl->mCachedRenderer->mKey );
+    }
+    mImpl->mCachedRenderer.Reset();
+
     actor.RemoveRenderer( mImpl->mRenderer );
     mImpl->mRenderer.Reset();
 
index 4dea2d9..10a13dc 100644 (file)
@@ -27,6 +27,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h>
 #include <dali-toolkit/devel-api/controls/renderer-factory/control-renderer.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
 
 namespace Dali
 {
@@ -37,8 +38,6 @@ namespace Toolkit
 namespace Internal
 {
 
-class RendererFactoryCache;
-
 /**
  * Base class for all Control rendering logic. A control may have multiple control renderers.
  *
@@ -68,10 +67,9 @@ public:
    *  request the geometry and shader from the cache, if not available, create and save to the cache for sharing;
    *  record the property values.
    *
-   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    * @param[in] propertyMap The properties for the requested ControlRenderer object.
    */
-  void Initialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
+  void Initialize( const Property::Map& propertyMap );
 
   /**
    * @copydoc Toolkit::ControlRenderer::SetSize
@@ -137,8 +135,10 @@ protected:
 
   /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  ControlRenderer();
+  ControlRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -159,7 +159,14 @@ protected:
    * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    * @param[in] propertyMap The properties for the requested ControlRenderer object.
    */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap ) = 0;
+  virtual void DoInitialize( const Property::Map& propertyMap ) = 0;
+
+  /**
+   * @brief Initialises a renderer ready to be put on stage.
+   *
+   * @param[inout] renderer The Renderer to initialise. If the renderer is not empty then re-initialise the renderer
+   */
+  virtual void InitializeRenderer( Renderer& renderer ) = 0;
 
 protected:
 
@@ -177,6 +184,15 @@ protected:
    */
   virtual void DoSetOffStage( Actor& actor );
 
+protected:
+
+  /**
+   * @brief Sets the key to use for caching the renderer. If this is empty then no caching will occur
+   *
+   * @param[in] cachedRendererKey The key to use for caching the renderer.
+   */
+  void SetCachedRendererKey( const std::string& cachedRendererKey );
+
 private:
 
   // Undefined
@@ -188,6 +204,7 @@ private:
 protected:
   struct Impl;
   Impl* mImpl;
+  RendererFactoryCache& mFactoryCache;
 };
 
 } // namespace Internal
index 0e502da..30a587f 100644 (file)
@@ -71,8 +71,28 @@ const char * const SPREAD_REPEAT("repeat");
 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
 const char * const UNIFORM_TEXTULRE_NAME("sTexture");
 
+RendererFactoryCache::ShaderType GetShaderType( GradientRenderer::Type type, Gradient::GradientUnits units)
+{
+  if( type==GradientRenderer::LINEAR )
+  {
+   if( units == Gradient::USER_SPACE_ON_USE )
+   {
+     return RendererFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
+   }
+   return RendererFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
+  }
+  else if( units == Gradient::USER_SPACE_ON_USE )
+  {
+    return RendererFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
+  }
 
-const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  return RendererFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
+}
+
+const char* VERTEX_SHADER[] =
+{
+// vertex shader for gradient units as USER_SPACE_ON_USE
+DALI_COMPOSE_SHADER(
   attribute mediump vec2 aPosition;\n
   uniform mediump mat4 uMvpMatrix;\n
   uniform mediump vec3 uSize;\n
@@ -87,9 +107,31 @@ const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
     \n
     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
   }\n
-);
+),
 
-const char* FRAGMENT_SHADER_LINEAR = DALI_COMPOSE_SHADER(
+// vertex shader for gradient units as OBJECT_BOUNDING_BOX
+ DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat3 uAlignmentMatrix;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
+    \n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+)
+};
+
+const char* FRAGMENT_SHADER[] =
+{
+// fragment shader for linear gradient
+DALI_COMPOSE_SHADER(
   uniform sampler2D sTexture;\n // sampler1D?
   uniform lowp vec4 uColor;\n
   varying mediump vec2 vTexCoord;\n
@@ -98,9 +140,10 @@ const char* FRAGMENT_SHADER_LINEAR = DALI_COMPOSE_SHADER(
   {\n
     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * uColor;\n
   }\n
-);
+),
 
-const char* FRAGMENT_SHADER_RADIAL = DALI_COMPOSE_SHADER(
+// fragment shader for radial gradient
+DALI_COMPOSE_SHADER(
   uniform sampler2D sTexture;\n // sampler1D?
   uniform lowp vec4 uColor;\n
   varying mediump vec2 vTexCoord;\n
@@ -109,7 +152,8 @@ const char* FRAGMENT_SHADER_RADIAL = DALI_COMPOSE_SHADER(
   {\n
     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * uColor;\n
   }\n
-);
+)
+};
 
 Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
 {
@@ -134,8 +178,9 @@ Sampler::WrapMode GetWrapMode( Gradient::SpreadMethod spread )
 }
 
 
-GradientRenderer::GradientRenderer()
-:mGradientTransformIndex( Property::INVALID_INDEX )
+GradientRenderer::GradientRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
+  mGradientType( LINEAR )
 {
 }
 
@@ -143,39 +188,27 @@ GradientRenderer::~GradientRenderer()
 {
 }
 
-void GradientRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void GradientRenderer::DoInitialize( const Property::Map& propertyMap )
 {
-  mImpl->mGeometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
-  if( !(mImpl->mGeometry) )
+  Gradient::GradientUnits gradientUnits = Gradient::OBJECT_BOUNDING_BOX;
+  Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
+  std::string units;
+  // The default unit is OBJECT_BOUNDING_BOX.
+  // Only need to set new units if 'user-space'
+  if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
   {
-    mImpl->mGeometry =  RendererFactoryCache::CreateQuadGeometry();
-    factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, mImpl->mGeometry );
+    gradientUnits = Gradient::USER_SPACE_ON_USE;
   }
 
-  Type gradientType;
+  mGradientType = LINEAR;
   if( propertyMap.Find( GRADIENT_RADIUS_NAME ))
   {
-    mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL );
-    if( !(mImpl->mShader) )
-    {
-      mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RADIAL );
-      factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_RADIAL, mImpl->mShader );
-    }
-    gradientType = RADIAL;
-  }
-  else
-  {
-    mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR );
-    if( !(mImpl->mShader) )
-    {
-      mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_LINEAR );
-      factoryCache.SaveShader( RendererFactoryCache::GRADIENT_SHADER_LINEAR, mImpl->mShader );
-    }
-    gradientType = LINEAR;
+    mGradientType = RADIAL;
   }
 
-  if( NewGradient(gradientType, propertyMap) )
+  if( NewGradient( mGradientType, propertyMap ) )
   {
+    mGradient->SetGradientUnits( gradientUnits );
     mGradientTransform = mGradient->GetAlignmentTransform();
   }
   else
@@ -187,19 +220,6 @@ void GradientRenderer::DoInitialize( RendererFactoryCache& factoryCache, const P
 void GradientRenderer::SetSize( const Vector2& size )
 {
   ControlRenderer::SetSize( size );
-
-  if( mGradient->GetGradientUnits() == Gradient::OBJECT_BOUNDING_BOX )
-  {
-    // Apply scaling
-    Matrix3 scaling( 1.f/(size.x+Math::MACHINE_EPSILON_100), 0.f, 0.f,
-                     0.f, 1.f/(size.y+Math::MACHINE_EPSILON_100), 0.f, 0.5f, 0.5f, 1.f );
-    Matrix3::Multiply( mGradientTransform, scaling, mGradient->GetAlignmentTransform() );
-
-    if( mImpl->mRenderer )
-    {
-      (mImpl->mRenderer).SetProperty( mGradientTransformIndex, mGradientTransform );
-    }
-  }
 }
 
 void GradientRenderer::SetClipRect( const Rect<int>& clipRect )
@@ -269,20 +289,48 @@ void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
   }
 }
 
-void GradientRenderer::DoSetOnStage( Actor& actor )
+void GradientRenderer::InitializeRenderer( Dali::Renderer& renderer )
 {
-  mGradientTransformIndex = (mImpl->mRenderer).RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
+  Geometry geometry = mFactoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
+  if( !geometry )
+  {
+    geometry =  RendererFactoryCache::CreateQuadGeometry();
+    mFactoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
+  }
+
+  Gradient::GradientUnits gradientUnits = mGradient->GetGradientUnits();
+  RendererFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
+  Shader shader = mFactoryCache.GetShader( shaderType );
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
+    mFactoryCache.SaveShader( shaderType, shader );
+  }
+
+  Material material;
+  if( !renderer )
+  {
+    material = Material::New( shader );
+    renderer = Renderer::New( geometry, material );
+  }
+  else
+  {
+    mImpl->mRenderer.SetGeometry( geometry );
+    material = mImpl->mRenderer.GetMaterial();
+    if( material )
+    {
+      material.SetShader( shader );
+    }
+  }
 
   Dali::BufferImage lookupTexture = mGradient->GenerateLookupTexture();
   Sampler sampler = Sampler::New( lookupTexture, UNIFORM_TEXTULRE_NAME );
   Sampler::WrapMode wrap = GetWrapMode( mGradient->GetSpreadMethod() );
   sampler.SetWrapMode(  wrap, wrap  );
 
-  Material material = (mImpl->mRenderer).GetMaterial();
-  if( material )
-  {
-    material.AddSampler( sampler );
-  }
+  material.AddSampler( sampler );
+
+  renderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
 }
 
 bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& propertyMap)
@@ -349,15 +397,6 @@ bool GradientRenderer::NewGradient(Type gradientType, const Property::Map& prope
     return false;
   }
 
-  Property::Value* unitsValue = propertyMap.Find( GRADIENT_UNITS_NAME );
-  std::string units;
-  // The default unit is OBJECT_BOUNDING_BOX.
-  // Only need to set new units if 'user-space'
-  if( unitsValue && unitsValue->Get( units ) && units == UNIT_USER_SPACE )
-  {
-     mGradient->SetGradientUnits( Gradient::USER_SPACE_ON_USE );
-  }
-
   Property::Value* spread = propertyMap.Find( GRADIENT_SPREAD_METHOD_NAME );
   std::string stringValue ;
   // The default spread method is PAD.
index 1ee3f36..deed3aa 100644 (file)
@@ -72,9 +72,20 @@ class GradientRenderer: public ControlRenderer
 public:
 
   /**
+   * Types of the gradient
+   */
+  enum Type
+  {
+    LINEAR,
+    RADIAL
+  };
+
+  /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  GradientRenderer();
+  GradientRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -84,11 +95,6 @@ public:
 public:  // from ControlRenderer
 
   /**
-   * @copydoc ControlRenderer::DoInitialize
-   */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
-  /**
    * @copydoc ControlRenderer::SetSize
    */
   virtual void SetSize( const Vector2& size );
@@ -110,20 +116,16 @@ public:  // from ControlRenderer
 
 protected:
   /**
-   * @copydoc ControlRenderer::DoSetOnStage
+   * @copydoc ControlRenderer::DoInitialize
    */
-  virtual void DoSetOnStage( Actor& actor );
-
-private:
+  virtual void DoInitialize( const Property::Map& propertyMap );
 
   /**
-   * Types of the gradient
+   * @copydoc ControlRenderer::InitializeRenderer
    */
-  enum Type
-  {
-    LINEAR,
-    RADIAL
-  };
+  virtual void InitializeRenderer( Renderer& renderer );
+
+private:
 
   /**
    * New a gradient object with the given property map.
@@ -150,8 +152,8 @@ private:
 private:
 
   Matrix3 mGradientTransform;
-  Property::Index mGradientTransformIndex;
   IntrusivePtr<Gradient> mGradient;
+  Type mGradientType;
 };
 
 } // namespace Internal
index 4770960..b595a48 100644 (file)
@@ -95,17 +95,6 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
   }\n
 );
 
-void AddQuadIndices( Vector< unsigned int >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
-{
-  indices.PushBack( rowIdx );
-  indices.PushBack( nextRowIdx + 1 );
-  indices.PushBack( rowIdx + 1 );
-
-  indices.PushBack( rowIdx );
-  indices.PushBack( nextRowIdx );
-  indices.PushBack( nextRowIdx + 1 );
-}
-
 Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
 {
   Property::Map vertexFormat;
@@ -128,6 +117,7 @@ Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsi
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( vertexPropertyBuffer );
   geometry.SetIndexBuffer( indexPropertyBuffer );
+  geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
 
   return geometry;
 }
@@ -164,15 +154,27 @@ Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gri
 
     // Create indices
     Vector< unsigned int > indices;
-    indices.Reserve( gridWidth * gridHeight * 6 );
+    indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
 
-    unsigned int rowIdx     = 0;
-    unsigned int nextRowIdx = gridWidth + 1;
-    for( int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx )
+    for( unsigned int row = 0u; row < gridHeight; ++row )
     {
-      for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+      unsigned int rowStartIndex = row*(gridWidth+1u);
+      unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
+
+      if( row != 0u ) // degenerate index on non-first row
       {
-        AddQuadIndices( indices, rowIdx, nextRowIdx );
+        indices.PushBack( rowStartIndex );
+      }
+
+      for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
+      {
+        indices.PushBack( rowStartIndex + column);
+        indices.PushBack( nextRowStartIndex + column);
+      }
+
+      if( row != gridHeight-1u ) // degenerate index on non-last row
+      {
+        indices.PushBack( nextRowStartIndex + gridWidth );
       }
     }
 
@@ -184,8 +186,8 @@ Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gri
 
 } //unnamed namespace
 
-ImageRenderer::ImageRenderer()
-: ControlRenderer(),
+ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
   mDesiredSize(),
   mFittingMode( FittingMode::DEFAULT ),
   mSamplingMode( SamplingMode::DEFAULT )
@@ -196,16 +198,15 @@ ImageRenderer::~ImageRenderer()
 {
 }
 
-void ImageRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void ImageRenderer::DoInitialize( const Property::Map& propertyMap )
 {
-  Initialize(factoryCache);
-
   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
   if( imageURLValue )
   {
     imageURLValue->Get( mImageUrl );
     if( !mImageUrl.empty() )
     {
+      SetCachedRendererKey( mImageUrl );
       mImage.Reset();
     }
 
@@ -344,6 +345,58 @@ void ImageRenderer::SetOffset( const Vector2& offset )
 {
 }
 
+void ImageRenderer::InitializeRenderer( Renderer& renderer )
+{
+  Geometry geometry;
+  Shader shader;
+  if( !mImpl->mCustomShader )
+  {
+    geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+
+    shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+      mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
+    }
+  }
+  else
+  {
+    geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
+
+    if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
+    {
+      shader = mFactoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+        mFactoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
+      }
+    }
+    else
+    {
+      shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
+                             mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
+                             mImpl->mCustomShader->mHints );
+    }
+  }
+
+  if( !renderer )
+  {
+    Material material = Material::New( shader );
+    renderer = Renderer::New( geometry, material );
+  }
+  else
+  {
+    renderer.SetGeometry( geometry );
+    Material material = renderer.GetMaterial();
+    if( material )
+    {
+      material.SetShader( shader );
+    }
+  }
+}
+
 void ImageRenderer::DoSetOnStage( Actor& actor )
 {
   if( !mImageUrl.empty() && !mImage )
@@ -459,53 +512,6 @@ void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
   }
 }
 
-void ImageRenderer::Initialize( RendererFactoryCache& factoryCache )
-{
-  if( !mImpl->mCustomShader )
-  {
-    mImpl->mGeometry = CreateGeometry( factoryCache, ImageDimensions( 1, 1 ) );
-
-    mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
-
-    if( !mImpl->mShader )
-    {
-      mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-      factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
-    }
-  }
-  else
-  {
-    mImpl->mGeometry = CreateGeometry( factoryCache, mImpl->mCustomShader->mGridSize );
-
-    if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
-    {
-      mImpl->mShader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
-
-      if( !mImpl->mShader )
-      {
-        mImpl->mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
-        factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, mImpl->mShader );
-      }
-    }
-    else
-    {
-      mImpl->mShader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
-                                    mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
-                                    mImpl->mCustomShader->mHints );
-    }
-  }
-
-  if( mImpl->mRenderer )
-  {
-    mImpl->mRenderer.SetGeometry( mImpl->mGeometry );
-    Material material = mImpl->mRenderer.GetMaterial();
-    if( material )
-    {
-      material.SetShader( mImpl->mShader );
-    }
-  }
-}
-
 void ImageRenderer::SetImage( const std::string& imageUrl )
 {
   SetImage( imageUrl, 0, 0, Dali::FittingMode::DEFAULT, Dali::SamplingMode::DEFAULT );
@@ -516,6 +522,7 @@ void ImageRenderer::SetImage( const std::string& imageUrl, int desiredWidth, int
   if( mImageUrl != imageUrl )
   {
     mImageUrl = imageUrl;
+    SetCachedRendererKey( mImageUrl );
     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
     mFittingMode = fittingMode;
     mSamplingMode = samplingMode;
index 367ae31..f408fb2 100644 (file)
@@ -74,8 +74,10 @@ public:
 
   /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  ImageRenderer();
+  ImageRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -85,11 +87,6 @@ public:
 public:  // from ControlRenderer
 
   /**
-   * @copydoc ControlRenderer::DoInitialize
-   */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
-  /**
    * @copydoc ControlRenderer::SetSize
    */
   virtual void SetSize( const Vector2& size );
@@ -116,6 +113,11 @@ public:  // from ControlRenderer
 
 protected:
   /**
+   * @copydoc ControlRenderer::DoInitialize
+   */
+  virtual void DoInitialize( const Property::Map& propertyMap );
+
+  /**
    * @copydoc ControlRenderer::DoSetOnStage
    */
   virtual void DoSetOnStage( Actor& actor );
@@ -125,14 +127,12 @@ protected:
    */
   virtual void DoSetOffStage( Actor& actor );
 
-public:
-
   /**
-   * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
-   *
-   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+   * @copydoc ControlRenderer::InitializeRenderer
    */
-  void Initialize( RendererFactoryCache& factoryCache );
+  virtual void InitializeRenderer( Renderer& renderer );
+
+public:
 
   /**
    * @brief Sets the image of this renderer to the resource at imageUrl
index 842a099..63e2f5d 100644 (file)
@@ -150,8 +150,8 @@ void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y )
 
 /////////////////NPatchRenderer////////////////
 
-NPatchRenderer::NPatchRenderer()
-: ControlRenderer(),
+NPatchRenderer::NPatchRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
   mBorderOnly( false )
 {
 }
@@ -160,10 +160,8 @@ NPatchRenderer::~NPatchRenderer()
 {
 }
 
-void NPatchRenderer::DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap )
+void NPatchRenderer::DoInitialize( const Property::Map& propertyMap )
 {
-  Initialize(factoryCache);
-
   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
   if( imageURLValue )
   {
@@ -217,6 +215,51 @@ void NPatchRenderer::SetOffset( const Vector2& offset )
   //ToDo: renderer applies the offset
 }
 
+void NPatchRenderer::InitializeRenderer( Renderer& renderer )
+{
+  Geometry geometry;
+  if( !mBorderOnly )
+  {
+    geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
+    if( !geometry )
+    {
+      geometry = CreateGeometry( Uint16Pair( 3, 3 ) );
+      mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry );
+    }
+  }
+  else
+  {
+    geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
+    if( !geometry )
+    {
+      geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
+      mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry );
+    }
+  }
+
+  Shader shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
+    mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
+  }
+
+  if( !renderer )
+  {
+    Material material = Material::New( shader );
+    renderer = Renderer::New( geometry, material );
+  }
+  else
+  {
+    mImpl->mRenderer.SetGeometry( geometry );
+    Material material = mImpl->mRenderer.GetMaterial();
+    if( material )
+    {
+      material.SetShader( shader );
+    }
+  }
+}
+
 void NPatchRenderer::DoSetOnStage( Actor& actor )
 {
   if( !mCroppedImage )
@@ -258,35 +301,6 @@ void NPatchRenderer::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( BORDER_ONLY, mBorderOnly );
 }
 
-void NPatchRenderer::Initialize( RendererFactoryCache& factoryCache )
-{
-  mNinePatchGeometry = factoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY );
-  if( !(mNinePatchGeometry) )
-  {
-    mNinePatchGeometry = CreateGeometry( Uint16Pair( 3, 3 ) );
-    factoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, mNinePatchGeometry );
-  }
-
-  mNinePatchBorderGeometry = factoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
-  if( !(mNinePatchBorderGeometry) )
-  {
-    mNinePatchBorderGeometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) );
-    factoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, mNinePatchBorderGeometry );
-  }
-
-  mNinePatchShader = factoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
-  if( !mNinePatchShader )
-  {
-    mNinePatchShader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
-    factoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, mNinePatchShader );
-  }
-
-  mImpl->mGeometry = mNinePatchGeometry;
-  mImpl->mShader = mNinePatchShader;
-
-  mImageUrl.clear();
-}
-
 void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly )
 {
   mBorderOnly = borderOnly;
@@ -338,13 +352,6 @@ void NPatchRenderer::InitialiseFromImage( NinePatchImage nPatch )
 
   mStretchPixelsX = nPatch.GetStretchPixelsX();
   mStretchPixelsY = nPatch.GetStretchPixelsY();
-
-  if( mStretchPixelsX.Size() > 0 && mStretchPixelsY.Size() > 0 )
-  {
-    //only 9 patch supported for now
-    mImpl->mGeometry = !mBorderOnly ? mNinePatchGeometry : mNinePatchBorderGeometry;
-    mImpl->mShader = mNinePatchShader;
-  }
 }
 
 void NPatchRenderer::CreateErrorImage()
@@ -367,9 +374,6 @@ void NPatchRenderer::CreateErrorImage()
   mStretchPixelsX.PushBack( Uint16Pair( 0, mImageSize.GetWidth() ) );
   mStretchPixelsY.Clear();
   mStretchPixelsY.PushBack( Uint16Pair( 0, mImageSize.GetHeight() ) );
-
-  mImpl->mGeometry = mNinePatchGeometry;
-  mImpl->mShader = mNinePatchShader;
 }
 
 void NPatchRenderer::ApplyImageToSampler()
index 6e5bd5d..77ba2a4 100644 (file)
@@ -55,8 +55,10 @@ public:
 
   /**
    * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
    */
-  NPatchRenderer();
+  NPatchRenderer( RendererFactoryCache& factoryCache );
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -66,11 +68,6 @@ public:
 public:  // from ControlRenderer
 
   /**
-   * @copydoc ControlRenderer::DoInitialize
-   */
-  virtual void DoInitialize( RendererFactoryCache& factoryCache, const Property::Map& propertyMap );
-
-  /**
    * @copydoc ControlRenderer::GetNaturalSize
    */
   virtual void GetNaturalSize( Vector2& naturalSize ) const;
@@ -91,6 +88,17 @@ public:  // from ControlRenderer
   virtual void DoCreatePropertyMap( Property::Map& map ) const;
 
 protected:
+
+  /**
+   * @copydoc ControlRenderer::DoInitialize
+   */
+  virtual void DoInitialize( const Property::Map& propertyMap );
+
+  /**
+   * @copydoc ControlRenderer::InitializeRenderer
+   */
+  virtual void InitializeRenderer( Renderer& renderer );
+
   /**
    * @copydoc ControlRenderer::DoSetOnStage
    */
@@ -104,13 +112,6 @@ protected:
 public:
 
   /**
-   * Request the geometry and shader from the cache, if not available, create and save to the cache for sharing.
-   *
-   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
-   */
-  void Initialize( RendererFactoryCache& factoryCache );
-
-  /**
    * @brief Sets the 9 patch image of this renderer to the resource at imageUrl
    * The renderer will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage
    *
@@ -184,7 +185,6 @@ private:
   Image mCroppedImage;
   Geometry mNinePatchGeometry;
   Geometry mNinePatchBorderGeometry;
-  Shader mNinePatchShader;
 
   std::string mImageUrl; ///< The url to the image resource to render if the renderer was set from an image resource url, empty otherwise
   NinePatchImage::StretchRanges mStretchPixelsX;
index cf8c47a..a22f541 100644 (file)
 // CLASS HEADER
 #include "renderer-factory-cache.h"
 
-// Internal HEADER
+// EXTERNAL HEADER
+#include <dali/devel-api/common/hash.h>
+
+// INTERNAL HEADER
 #include <dali-toolkit/internal/controls/renderers/color/color-renderer.h>
 
 namespace Dali
@@ -35,24 +38,8 @@ RendererFactoryCache::RendererFactoryCache()
 
 RendererFactoryCache::~RendererFactoryCache()
 {
-  for( int i=0; i<= SHADER_TYPE_MAX; i++)
-  {
-    if(mShader[i])
-    {
-      mShader[i].Reset();
-    }
-  }
-
-  for( int i=0; i<= GEOMETRY_TYPE_MAX; i++)
-  {
-    if(mGeometry[i])
-    {
-      mGeometry[i].Reset();
-    }
-  }
 }
 
-
 Geometry RendererFactoryCache::GetGeometry( GeometryType type )
 {
   return mGeometry[type];
@@ -73,6 +60,80 @@ void RendererFactoryCache::SaveShader( ShaderType type, Shader shader )
   mShader[type] = shader;
 }
 
+int RendererFactoryCache::FindRenderer( const std::string& key ) const
+{
+  int hash = Dali::CalculateHash( key );
+
+  HashVector::Iterator startIt = mRendererHashes.Begin();
+  HashVector::Iterator it;
+
+  for(;;)
+  {
+    it = std::find( startIt, mRendererHashes.End(), hash );
+    if( it != mRendererHashes.End() )
+    {
+      int index = it - mRendererHashes.Begin();
+      const CachedRendererPtr& cachedRenderer = mRenderers[ index ];
+
+      if( cachedRenderer && cachedRenderer->mKey == key )
+      {
+        return index;
+      }
+    }
+    else
+    {
+      break;
+    }
+    startIt = it + 1;
+  }
+
+  return -1;
+}
+
+RendererFactoryCache::CachedRendererPtr RendererFactoryCache::GetRenderer( const std::string& key ) const
+{
+  int index = FindRenderer( key );
+  if( index != -1 )
+  {
+    return mRenderers[ index ];
+  }
+  else
+  {
+    return CachedRendererPtr();
+  }
+}
+
+RendererFactoryCache::CachedRendererPtr RendererFactoryCache::SaveRenderer( const std::string& key, Renderer& renderer )
+{
+  int hash = Dali::CalculateHash( key );
+  CachedRendererPtr newCachedRenderer = new CachedRenderer( key, renderer );
+
+  CachedRenderers::iterator it = std::find(mRenderers.begin(), mRenderers.end(), CachedRendererPtr() );
+  if( it != mRenderers.end() )
+  {
+    *it = newCachedRenderer;
+    int index = it - mRenderers.begin();
+    mRendererHashes[ index ] = hash;
+  }
+  else
+  {
+    mRendererHashes.PushBack( hash );
+    mRenderers.push_back( newCachedRenderer );
+  }
+
+  return newCachedRenderer;
+}
+
+void RendererFactoryCache::RemoveRenderer( const std::string& key )
+{
+  int index = FindRenderer( key );
+  if( index != -1 )
+  {
+    mRendererHashes[ index ] = Dali::CalculateHash( "" );
+    mRenderers[ index ].Reset();
+  }
+}
+
 Geometry RendererFactoryCache::CreateQuadGeometry()
 {
   const float halfWidth = 0.5f;
@@ -91,18 +152,10 @@ Geometry RendererFactoryCache::CreateQuadGeometry()
   PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat, 4 );
   quadVertices.SetData(quadVertexData);
 
-  // Create indices
-  //TODO: replace with triangle strip when Geometry supports it
-  unsigned int indexData[6] = { 0, 3, 1, 0, 2, 3 };
-  Property::Map indexFormat;
-  indexFormat["indices"] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat, 6 );
-  indices.SetData(indexData);
-
   // Create the geometry object
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( quadVertices );
-  geometry.SetIndexBuffer( indices );
+  geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
 
   return geometry;
 }
index ab589c2..f546c85 100644 (file)
  * limitations under the License.
  */
 
+#include <map>
+
 // EXTERNAL INCLUDES
 #include <dali/public-api/object/ref-object.h>
 #include <dali/devel-api/rendering/geometry.h>
 #include <dali/devel-api/rendering/shader.h>
+#include <dali/devel-api/rendering/renderer.h>
 
 namespace Dali
 {
@@ -45,8 +48,10 @@ public:
   {
     COLOR_SHADER,
     BORDER_SHADER,
-    GRADIENT_SHADER_LINEAR,
-    GRADIENT_SHADER_RADIAL,
+    GRADIENT_SHADER_LINEAR_USER_SPACE,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+    GRADIENT_SHADER_RADIAL_USER_SPACE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
     IMAGE_SHADER,
     NINE_PATCH_SHADER,
     SVG_SHADER,
@@ -104,6 +109,47 @@ public:
    */
   static Geometry CreateQuadGeometry();
 
+public:
+  struct CachedRenderer : RefObject
+  {
+    std::string mKey;
+    Renderer mRenderer;
+
+    CachedRenderer( const std::string& key, const Renderer& renderer )
+    : mKey( key ),
+      mRenderer( renderer )
+    {}
+  };
+
+  typedef IntrusivePtr< CachedRenderer > CachedRendererPtr;
+
+  /**
+   * @brief Request renderer from the url
+   *
+   * @return The cached renderer if exist in the cache. Otherwise null is returned.
+   */
+  CachedRendererPtr GetRenderer( const std::string& key ) const;
+
+  /**
+   * @brief Cache the renderer based on the given key.
+   *
+   * If the key already exists in the cache, then the cache will save an additional renderer to the cache.
+   * RemoveRenderer will then need to be called twice to remove both items from the cache.
+   *
+   * @param[in] key The key to use for caching
+   * @param[in] renderer The Renderer to be cached
+   *
+   * @return The cached renderer stored in the cache
+   */
+  CachedRendererPtr SaveRenderer( const std::string& key, Renderer& renderer );
+
+  /**
+   * @brief Removes the renderer from the cache based on the given key
+   *
+   * @param[in] key The key used for caching
+   */
+  void RemoveRenderer( const std::string& key );
+
 protected:
 
   /**
@@ -122,12 +168,25 @@ protected:
   RendererFactoryCache& operator=(const RendererFactoryCache& rhs);
 
 private:
+  typedef Dali::Vector< std::size_t > HashVector;
+  typedef std::vector< CachedRendererPtr > CachedRenderers;
 
+  /**
+   * @brief Finds the first index into the cached renderers from the url
+   *
+   * @return Returns the first index into the cached renderer from the url if it exists in the cache, otherwise returns -1
+   */
+  int FindRenderer( const std::string& key ) const;
+
+private:
   // ToDo: test whether using the WeakHandle could improve the performance
   //       With WeakHandle, the resource would be released automatically when no control is using it
 
   Geometry mGeometry[GEOMETRY_TYPE_MAX+1];
   Shader mShader[SHADER_TYPE_MAX+1];
+
+  HashVector mRendererHashes;
+  CachedRenderers mRenderers;
 };
 
 } // namespace Internal
index afcc452..b9d1d40 100644 (file)
@@ -83,35 +83,36 @@ Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Ma
   std::string typeValue ;
   if( type && type->Get( typeValue ))
   {
+    if( !mFactoryCache )
+    {
+      mFactoryCache = new RendererFactoryCache();
+    }
+
     if( typeValue ==  COLOR_RENDERER )
     {
-      rendererPtr = new ColorRenderer();
+      rendererPtr = new ColorRenderer( *( mFactoryCache.Get() ) );
     }
     else if( typeValue ==  GRADIENT_RENDERER )
     {
-      rendererPtr = new GradientRenderer();
+      rendererPtr = new GradientRenderer( *( mFactoryCache.Get() ) );
     }
     else if( typeValue ==  IMAGE_RENDERER )
     {
-      rendererPtr = new ImageRenderer();
+      rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
     }
     else if( typeValue ==  N_PATCH_RENDERER )
     {
-      rendererPtr = new NPatchRenderer();
+      rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
     }
     else if( typeValue == BORDER_RENDERER )
     {
-      rendererPtr = new BorderRenderer();
+      rendererPtr = new BorderRenderer( *( mFactoryCache.Get() ) );
     }
   }
 
   if( rendererPtr )
   {
-    if( !mFactoryCache )
-    {
-      mFactoryCache = new RendererFactoryCache();
-    }
-    rendererPtr->Initialize( *( mFactoryCache.Get() ), propertyMap );
+    rendererPtr->Initialize( propertyMap );
   }
   else
   {
@@ -123,14 +124,12 @@ Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Ma
 
 Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Vector4& color )
 {
-  ColorRenderer* rendererPtr = new ColorRenderer();
-
   if( !mFactoryCache )
   {
     mFactoryCache = new RendererFactoryCache();
   }
-  rendererPtr->Initialize( *( mFactoryCache.Get() ) );
 
+  ColorRenderer* rendererPtr = new ColorRenderer( *( mFactoryCache.Get() ) );
   rendererPtr->SetColor( color );
 
   return Toolkit::ControlRenderer( rendererPtr );
@@ -153,13 +152,16 @@ bool RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const V
 
 Toolkit::ControlRenderer RendererFactory::GetControlRenderer( float borderSize, const Vector4& borderColor )
 {
-  BorderRenderer* rendererPtr = new BorderRenderer();
+  if( !mFactoryCache )
+  {
+    mFactoryCache = new RendererFactoryCache();
+  }
+  BorderRenderer* rendererPtr = new BorderRenderer( *mFactoryCache.Get() );
 
   if( !mFactoryCache )
   {
     mFactoryCache = new RendererFactoryCache();
   }
-  rendererPtr->Initialize( *( mFactoryCache.Get() ) );
 
   rendererPtr->SetBorderSize( borderSize );
   rendererPtr->SetBorderColor( borderColor );
@@ -177,16 +179,14 @@ Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Image& image
   NinePatchImage npatchImage = NinePatchImage::DownCast( image );
   if( npatchImage )
   {
-    NPatchRenderer* rendererPtr = new NPatchRenderer();
-    rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+    NPatchRenderer* rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
     rendererPtr->SetImage( npatchImage );
 
     return Toolkit::ControlRenderer( rendererPtr );
   }
   else
   {
-    ImageRenderer* rendererPtr = new ImageRenderer();
-    rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+    ImageRenderer* rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
     rendererPtr->SetImage( image );
 
     return Toolkit::ControlRenderer( rendererPtr );
@@ -221,26 +221,21 @@ bool RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const I
 
 Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const std::string& url )
 {
+  if( !mFactoryCache )
+  {
+    mFactoryCache = new RendererFactoryCache();
+  }
+
   if( NinePatchImage::IsNinePatchUrl( url ) )
   {
-    NPatchRenderer* rendererPtr = new NPatchRenderer();
-    if( !mFactoryCache )
-    {
-      mFactoryCache = new RendererFactoryCache();
-    }
-    rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+    NPatchRenderer* rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
     rendererPtr->SetImage( url );
 
     return Toolkit::ControlRenderer( rendererPtr );
   }
   else
   {
-    ImageRenderer* rendererPtr = new ImageRenderer();
-    if( !mFactoryCache )
-    {
-      mFactoryCache = new RendererFactoryCache();
-    }
-    rendererPtr->Initialize( *( mFactoryCache.Get() ) );
+    ImageRenderer* rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ) );
     rendererPtr->SetImage( url );
 
     return Toolkit::ControlRenderer( rendererPtr );
@@ -308,11 +303,7 @@ bool RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, const P
     }
   }
 
-  if( !mFactoryCache )
-  {
-    mFactoryCache = new RendererFactoryCache();
-  }
-  GetImplementation( renderer ).Initialize( *( mFactoryCache.Get() ), propertyMap );
+  GetImplementation( renderer ).Initialize( propertyMap );
   return false;
 }
 
index f5dda09..9fe5771 100644 (file)
@@ -889,7 +889,7 @@ void TextField::OnInitialize()
   mController->EnableTextInput( mDecorator );
 
   // Forward input events to controller
-  EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan |Gesture::LongPress ) );
+  EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
   GetTapGestureDetector().SetMaximumTapsRequired( 2 );
 
   self.TouchedSignal().Connect( this, &TextField::OnTouched );
@@ -904,6 +904,9 @@ void TextField::OnInitialize()
     mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
   }
 
+  // Flip vertically the 'left' selection handle
+  mDecorator->FlipHandleVertically( LEFT_SELECTION_HANDLE, true );
+
   // Fill-parent area by default
   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
index 153b34c..be24d2b 100644 (file)
@@ -442,7 +442,10 @@ void TextLabel::OnInitialize()
 
   // Enable the text ellipsis.
   LayoutEngine& engine = mController->GetLayoutEngine();
+
   engine.SetTextEllipsisEnabled( true );
+  engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
+
   self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
 }
 
index 6541b77..1af079c 100644 (file)
@@ -85,9 +85,6 @@ Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLog
 // Local Data
 namespace
 {
-
-const char* DEFAULT_GRAB_HANDLE_IMAGE_RELEASED( DALI_IMAGE_DIR "cursor_handler_center.png" );
-
 const int DEFAULT_POPUP_OFFSET( -100.0f ); // Vertical offset of Popup from cursor or handles position.
 
 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
@@ -219,6 +216,7 @@ struct Decorator::Impl : public ConnectionTracker
       active( false ),
       visible( false ),
       pressed( false ),
+      verticallyFlippedPreferred( false ),
       horizontallyFlipped( false ),
       verticallyFlipped( false )
     {
@@ -236,8 +234,9 @@ struct Decorator::Impl : public ConnectionTracker
     bool    active  : 1;
     bool    visible : 1;
     bool    pressed : 1;
-    bool    horizontallyFlipped : 1; ///< Whether the handle has been horizontally flipped.
-    bool    verticallyFlipped   : 1; ///< Whether the handle has been vertically flipped.
+    bool    verticallyFlippedPreferred : 1; ///< Whether the handle is preferred to be vertically flipped.
+    bool    horizontallyFlipped        : 1; ///< Whether the handle has been horizontally flipped.
+    bool    verticallyFlipped          : 1; ///< Whether the handle has been vertically flipped.
   };
 
   struct PopupImpl
@@ -308,13 +307,11 @@ struct Decorator::Impl : public ConnectionTracker
     if( mPrimaryCursor )
     {
       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
-      mPrimaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
+      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
       if( mPrimaryCursorVisible )
       {
-        const Vector2& position = cursor.position;
-
-        mPrimaryCursor.SetPosition( position.x,
-                                    position.y );
+        mPrimaryCursor.SetPosition( cursor.position.x,
+                                    cursor.position.y );
         mPrimaryCursor.SetSize( Size( mCursorWidth, cursor.cursorHeight ) );
       }
       mPrimaryCursor.SetVisible( mPrimaryCursorVisible && mCursorBlinkStatus );
@@ -322,7 +319,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mSecondaryCursor )
     {
       const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
-      mSecondaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
+      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
       if( mSecondaryCursorVisible )
       {
         mSecondaryCursor.SetPosition( cursor.position.x,
@@ -336,9 +333,7 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
     if( grabHandle.active )
     {
-      const Vector2& position = grabHandle.position;
-
-      const bool isVisible = ( position.x <= size.width ) && ( position.x >= 0.f );
+      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= size.width ) && ( grabHandle.position.x >= 0.f );
 
       if( isVisible )
       {
@@ -350,7 +345,11 @@ struct Decorator::Impl : public ConnectionTracker
         // Sets the grab handle image according if it's pressed, flipped, etc.
         SetHandleImage( GRAB_HANDLE );
       }
-      grabHandle.actor.SetVisible( isVisible );
+
+      if( grabHandle.actor )
+      {
+        grabHandle.actor.SetVisible( isVisible );
+      }
     }
     else if( grabHandle.actor )
     {
@@ -362,11 +361,8 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
     if( primary.active || secondary.active )
     {
-      const Vector2& primaryPosition = primary.position;
-      const 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 );
+      const bool isPrimaryVisible = ( primary.position.x <= size.width ) && ( primary.position.x >= 0.f );
+      const bool isSecondaryVisible = ( secondary.position.x <= size.width ) && ( secondary.position.x >= 0.f );
 
       if( isPrimaryVisible || isSecondaryVisible )
       {
@@ -392,8 +388,15 @@ struct Decorator::Impl : public ConnectionTracker
           SetSelectionHandleMarkerSize( secondary );
         }
       }
-      primary.actor.SetVisible( isPrimaryVisible );
-      secondary.actor.SetVisible( isSecondaryVisible );
+
+      if( primary.actor )
+      {
+        primary.actor.SetVisible( isPrimaryVisible );
+      }
+      if( secondary.actor )
+      {
+        secondary.actor.SetVisible( isSecondaryVisible );
+      }
 
       CreateHighlight();
       UpdateHighlight();
@@ -619,7 +622,7 @@ struct Decorator::Impl : public ConnectionTracker
 
   void SetSelectionHandleMarkerSize( HandleImpl& handle )
   {
-    if ( handle.markerActor )
+    if( handle.markerActor )
     {
       handle.markerActor.SetSize( 0, handle.lineHeight );
     }
@@ -630,11 +633,6 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
     if( !grabHandle.actor )
     {
-      if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
-      {
-        SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_RELEASED ) );
-      }
-
       grabHandle.actor = ImageActor::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
       grabHandle.actor.SetSortModifier( DECORATION_DEPTH_INDEX );
       grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
@@ -677,7 +675,7 @@ struct Decorator::Impl : public ConnectionTracker
 
   void CreateHandleMarker( HandleImpl& handle, Image& image, HandleType handleType )
   {
-    if ( image )
+    if( image )
     {
       handle.markerActor = ImageActor::New( image );
       handle.markerActor.SetColor( mHandleColor );
@@ -685,12 +683,12 @@ struct Decorator::Impl : public ConnectionTracker
 
       handle.markerActor.SetResizePolicy ( ResizePolicy::FIXED, Dimension::HEIGHT );
 
-      if ( LEFT_SELECTION_HANDLE == handleType )
+      if( LEFT_SELECTION_HANDLE == handleType )
       {
         handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
         handle.markerActor.SetParentOrigin( ParentOrigin::TOP_RIGHT );
       }
-      else if ( RIGHT_SELECTION_HANDLE == handleType )
+      else if( RIGHT_SELECTION_HANDLE == handleType )
       {
         handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
         handle.markerActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
@@ -794,7 +792,10 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Check if the grab handle exceeds the boundaries of the decoration box.
     // At the moment only the height is checked for the grab handle.
-    grabHandle.verticallyFlipped = ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
+
+    grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
+                                     ( ( grabHandleWorldPosition.y - grabHandle.lineHeight - grabHandle.size.height ) > mBoundingBox.y ) ) ||
+                                   ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
 
     // The grab handle 'y' position in local coords.
     // If the grab handle exceeds the bottom of the decoration box,
@@ -802,7 +803,7 @@ struct Decorator::Impl : public ConnectionTracker
     // The SetGrabHandleImage() method will change the orientation.
     const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
 
-    grabHandle.actor.SetPosition( grabHandle.position.x - floor( 0.5f * mCursorWidth ),
+    grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ),
                                   yLocalPosition ); // TODO : Fix for multiline.
   }
 
@@ -817,7 +818,7 @@ struct Decorator::Impl : public ConnectionTracker
     Vector2 handleWorldPosition;
     CalculateHandleWorldCoordinates( handle, handleWorldPosition );
 
-    // Whether to flip the handle.
+    // Whether to flip the handle (horizontally).
     bool flipHandle = isPrimaryHandle ? mFlipLeftSelectionHandleDirection : mFlipRightSelectionHandleDirection;
 
     // Whether to flip the handles if they are crossed.
@@ -830,6 +831,21 @@ struct Decorator::Impl : public ConnectionTracker
     // Does not flip if both conditions are true (double flip)
     flipHandle = flipHandle != ( crossFlip || mHandlePreviousCrossed );
 
+    // Will flip the handles vertically if the user prefers it.
+    bool verticallyFlippedPreferred = handle.verticallyFlippedPreferred;
+
+    if( crossFlip || mHandlePreviousCrossed )
+    {
+      if( isPrimaryHandle )
+      {
+        verticallyFlippedPreferred = mHandle[RIGHT_SELECTION_HANDLE].verticallyFlippedPreferred;
+      }
+      else
+      {
+        verticallyFlippedPreferred = mHandle[LEFT_SELECTION_HANDLE].verticallyFlippedPreferred;
+      }
+    }
+
     // Check if the selection handle exceeds the boundaries of the decoration box.
     const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
 
@@ -860,7 +876,9 @@ struct Decorator::Impl : public ConnectionTracker
     }
 
     // Whether to flip the handle vertically.
-    handle.verticallyFlipped = ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
+    handle.verticallyFlipped = ( verticallyFlippedPreferred &&
+                                 ( ( handleWorldPosition.y - handle.lineHeight - handle.size.height ) > mBoundingBox.y ) ) ||
+                               ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
 
     // The primary selection handle 'y' position in local coords.
     // If the handle exceeds the bottom of the decoration box,
@@ -890,18 +908,27 @@ struct Decorator::Impl : public ConnectionTracker
     }
 
     // Chooses between the released or pressed image. It checks whether the pressed image exists.
-    const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+    if( handle.actor )
+    {
+      const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
 
-    handle.actor.SetImage( mHandleImages[type][imageType] );
+      handle.actor.SetImage( mHandleImages[type][imageType] );
+    }
 
     if( HANDLE_TYPE_COUNT != markerType )
     {
-      const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
-      handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
+      if( handle.markerActor )
+      {
+        const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+        handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
+      }
     }
 
     // Whether to flip the handle vertically.
-    handle.actor.SetOrientation( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS );
+    if( handle.actor )
+    {
+      handle.actor.SetOrientation( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS );
+    }
   }
 
   void CreateHighlight()
@@ -1192,26 +1219,34 @@ struct Decorator::Impl : public ConnectionTracker
 
   float AlternatePopUpPositionRelativeToCursor()
   {
+    const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
+    const float BOTTOM_HANDLE_BOTTOM_OFFSET = 1.5; //todo Should be a property
+
     float alternativePosition=0.0f;;
 
-    if ( mPrimaryCursor ) // Secondary cursor not used for paste
+    if( mPrimaryCursor ) // Secondary cursor not used for paste
     {
-      Cursor cursor = PRIMARY_CURSOR;
-      alternativePosition = mCursor[cursor].position.y;
+      alternativePosition = mCursor[PRIMARY_CURSOR].position.y + popupHeight;
     }
 
-    const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    const HandleImpl& selectionPrimaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& selectionSecondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
 
-    if( mHandle[GRAB_HANDLE].active )
+    if( grabHandle.active )
     {
       // If grab handle enabled then position pop-up below the grab handle.
-      const Vector2 grabHandleSize( 59.0f, 56.0f ); // todo
-      const float BOTTOM_HANDLE_BOTTOM_OFFSET = 1.5; //todo Should be a property
-      alternativePosition +=  grabHandleSize.height  + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET ;
+      alternativePosition = grabHandle.position.y + grabHandle.size.height + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
+
     }
-    else
+    else if( selectionPrimaryHandle.active || selectionSecondaryHandle.active )
     {
-      alternativePosition += popupHeight;
+      const float maxHeight = std::max( selectionPrimaryHandle.size.height,
+                                        selectionSecondaryHandle.size.height );
+      const float maxY = std::max( selectionPrimaryHandle.position.y,
+                                   selectionSecondaryHandle.position.y );
+
+      alternativePosition = maxY + maxHeight + popupHeight + BOTTOM_HANDLE_BOTTOM_OFFSET;
     }
 
     return alternativePosition;
@@ -1227,7 +1262,6 @@ struct Decorator::Impl : public ConnectionTracker
     mCopyPastePopup.actor.SetY( alternativeYPosition );
   }
 
-
   void SetUpPopupPositionNotifications( )
   {
     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
@@ -1634,6 +1668,16 @@ const Vector2& Decorator::GetPosition( HandleType handleType ) const
   return mImpl->mHandle[handleType].position;
 }
 
+void Decorator::FlipHandleVertically( HandleType handleType, bool flip )
+{
+  mImpl->mHandle[handleType].verticallyFlippedPreferred = flip;
+}
+
+bool Decorator::IsHandleVerticallyFlipped( HandleType handleType ) const
+{
+  return mImpl->mHandle[handleType].verticallyFlippedPreferred;
+}
+
 void Decorator::FlipSelectionHandlesOnCrossEnabled( bool enable )
 {
   mImpl->mFlipSelectionHandlesOnCross = enable;
index 4e36fa7..4bcd012 100644 (file)
@@ -397,6 +397,23 @@ public:
   const Vector2& GetPosition( HandleType handleType ) const;
 
   /**
+   * @brief Whether to flip vertically a handle.
+   *
+   * @param[in] handleType The handle to flip vertically.
+   * @param[in] flip Whether to flip vertically.
+   */
+  void FlipHandleVertically( HandleType handleType, bool flip );
+
+  /**
+   * @brief Retrieves whether the handle is vertically flipped.
+   *
+   * @param[in] handleType The handle to query.
+   *
+   * @return @e ture if the handle is vertically flipped.
+   */
+  bool IsHandleVerticallyFlipped( HandleType handleType ) const;
+
+  /**
    * @brief Whether to flip the selection handles as soon as they are crossed.
    *
    * By default they flip when the handle is released.
index 9062b07..54a957c 100644 (file)
@@ -451,7 +451,6 @@ struct LayoutEngine::Impl
 
     const GlyphInfo& glyph = *glyphsBuffer;
     float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
-    penX += mCursorWidth; // Added to give some space to the cursor.
 
     for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
     {
@@ -672,7 +671,6 @@ struct LayoutEngine::Impl
       const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
 
       float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
-      penX += mCursorWidth; // Added to give some space to the cursor.
 
       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
 
index bd66860..e6a8b18 100644 (file)
@@ -200,62 +200,81 @@ bool Controller::Impl::ProcessInputEvents()
   if( mEventData->mUpdateCursorPosition )
   {
     // Updates the cursor position and scrolls the text to make it visible.
-
-    UpdateCursorPosition();
+    CursorInfo cursorInfo;
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
 
     if( mEventData->mScrollAfterUpdatePosition )
     {
-      const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
-
-      ScrollToMakePositionVisible( primaryCursorPosition );
+      ScrollToMakePositionVisible( cursorInfo.primaryPosition );
       mEventData->mScrollAfterUpdatePosition = false;
     }
+    else if( mEventData->mScrollAfterDelete )
+    {
+      ScrollTextToMatchCursor( cursorInfo );
+      mEventData->mScrollAfterDelete = false;
+    }
+
+    UpdateCursorPosition( cursorInfo );
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
-  else if( mEventData->mScrollAfterDelete )
-  {
-    ScrollTextToMatchCursor();
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mScrollAfterDelete = false;
-  }
   else
   {
     bool leftScroll = false;
     bool rightScroll = false;
 
+    CursorInfo leftHandleInfo;
+    CursorInfo rightHandleInfo;
+
     if( mEventData->mUpdateLeftSelectionPosition )
     {
-      UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+      GetCursorPosition( mEventData->mLeftSelectionPosition,
+                         leftHandleInfo );
 
       if( mEventData->mScrollAfterUpdatePosition )
       {
-        const Vector2& leftHandlePosition = mEventData->mDecorator->GetPosition( LEFT_SELECTION_HANDLE );
-
-        ScrollToMakePositionVisible( leftHandlePosition );
+        ScrollToMakePositionVisible( leftHandleInfo.primaryPosition );
         leftScroll = true;
       }
-
-      SetPopupButtons();
-      mEventData->mDecoratorUpdated = true;
-      mEventData->mUpdateLeftSelectionPosition = false;
     }
 
     if( mEventData->mUpdateRightSelectionPosition )
     {
-      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+      GetCursorPosition( mEventData->mRightSelectionPosition,
+                         rightHandleInfo );
 
       if( mEventData->mScrollAfterUpdatePosition )
       {
-        const Vector2& rightHandlePosition = mEventData->mDecorator->GetPosition( RIGHT_SELECTION_HANDLE );
-
-        ScrollToMakePositionVisible( rightHandlePosition );
+        ScrollToMakePositionVisible( rightHandleInfo.primaryPosition );
         rightScroll = true;
       }
+    }
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
+                             leftHandleInfo );
 
       SetPopupButtons();
       mEventData->mDecoratorUpdated = true;
+    }
+
+    if( mEventData->mUpdateRightSelectionPosition )
+    {
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
+                             rightHandleInfo );
+
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+    }
+
+    if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+    {
+      RepositionSelectionHandles();
+
+      mEventData->mUpdateLeftSelectionPosition = false;
       mEventData->mUpdateRightSelectionPosition = false;
     }
 
@@ -646,9 +665,6 @@ void Controller::Impl::OnHandleEvent( const Event& event )
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
 
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
-
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
@@ -661,9 +677,6 @@ void Controller::Impl::OnHandleEvent( const Event& event )
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
 
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
-
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
@@ -705,9 +718,6 @@ void Controller::Impl::OnHandleEvent( const Event& event )
         if( mEventData->mUpdateLeftSelectionPosition )
         {
           mEventData->mLeftSelectionPosition = handlePosition;
-
-          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                      mEventData->mRightSelectionPosition );
         }
       }
     }
@@ -722,8 +732,6 @@ void Controller::Impl::OnHandleEvent( const Event& event )
         if( mEventData->mUpdateRightSelectionPosition )
         {
           mEventData->mRightSelectionPosition = handlePosition;
-          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                      mEventData->mRightSelectionPosition );
         }
       }
     }
@@ -811,8 +819,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
       {
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
+        RepositionSelectionHandles();
 
         mEventData->mScrollAfterUpdatePosition = true;
       }
@@ -835,17 +842,14 @@ void Controller::Impl::OnSelectEvent( const Event& event )
     const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
     const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
-    const CharacterIndex leftPosition = mEventData->mLeftSelectionPosition;
-    const CharacterIndex rightPosition = mEventData->mRightSelectionPosition;
-
+    // Calculates the logical position from the x,y coords.
     RepositionSelectionHandles( xPosition,
                                 yPosition );
 
-    mEventData->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
-    mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
 
-    mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
-                                               ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
+    mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
   }
 }
 
@@ -859,8 +863,8 @@ void Controller::Impl::OnSelectAllEvent()
 
   if( mEventData->mSelectionEnabled )
   {
-    RepositionSelectionHandles( 0u,
-                                mLogicalModel->mText.Count() );
+    mEventData->mLeftSelectionPosition = 0u;
+    mEventData->mRightSelectionPosition = mLogicalModel->mText.Count();
 
     mEventData->mScrollAfterUpdatePosition = true;
     mEventData->mUpdateLeftSelectionPosition = true;
@@ -899,9 +903,15 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete
       Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
       currentText.Erase( first, last );
+
+      // Scroll after delete.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+      mEventData->mScrollAfterDelete = true;
     }
-    mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
-    mEventData->mScrollAfterDelete = true;
+    // Udpade the cursor position and the decorator.
+    // Scroll after the position is updated if is not scrolling after delete.
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mScrollAfterUpdatePosition = !mEventData->mScrollAfterDelete;
     mEventData->mDecoratorUpdated = true;
   }
 }
@@ -944,8 +954,11 @@ void Controller::Impl::GetTextFromClipboard( unsigned int itemIndex, std::string
   }
 }
 
-void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd )
+void Controller::Impl::RepositionSelectionHandles()
 {
+  CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
+  CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
+
   if( selectionStart == selectionEnd )
   {
     // Nothing to select if handles are in the same place.
@@ -954,9 +967,6 @@ void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart
 
   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();
@@ -1128,7 +1138,8 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
     return;
   }
 
-  RepositionSelectionHandles( selectionStart, selectionEnd );
+  mEventData->mLeftSelectionPosition = selectionStart;
+  mEventData->mRightSelectionPosition = selectionEnd;
 }
 
 void Controller::Impl::SetPopupButtons()
@@ -1143,7 +1154,7 @@ void Controller::Impl::SetPopupButtons()
 
   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
 
-  if ( ( EventData::SELECTING == mEventData->mState ) || ( EventData::SELECTION_CHANGED == mEventData->mState ) )
+  if( EventData::SELECTING == mEventData->mState )
   {
     buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
 
@@ -1221,16 +1232,6 @@ void Controller::Impl::ChangeState( EventData::State newState )
       }
       mEventData->mDecoratorUpdated = true;
     }
-    else if ( EventData::SELECTION_CHANGED  == mEventData->mState )
-    {
-      if( mEventData->mGrabHandlePopupEnabled )
-      {
-        SetPopupButtons();
-        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
-        mEventData->mDecorator->SetPopupActive( true );
-      }
-      mEventData->mDecoratorUpdated = true;
-    }
     else if( EventData::EDITING == mEventData->mState )
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
@@ -1517,23 +1518,64 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 {
   // TODO: Check for multiline with \n, etc...
 
-  // Check if the logical position is the first or the last one of the text.
-  const bool isFirstPosition = 0u == logical;
-  const bool isLastPosition = mLogicalModel->mText.Count() == logical;
-
-  if( isFirstPosition && isLastPosition )
+  const Length numberOfCharacters = mLogicalModel->mText.Count();
+  if( !IsShowingRealText() )
   {
-    // There is zero characters. Get the default font's line height.
+    // Do not want to use the place-holder text to set the cursor position.
+
+    // Use the line's height of the font's family set to set the cursor's size.
+    // If there is no font's family set, use the default font.
+    // Use the current alignment to place the cursor at the beginning, center or end of the box.
+
     cursorInfo.lineHeight = GetDefaultFontLineHeight();
     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
-    cursorInfo.primaryPosition.x = 0.f;
-    cursorInfo.primaryPosition.y = 0.f;
+    switch( mLayoutEngine.GetHorizontalAlignment() )
+    {
+      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
+      {
+        cursorInfo.primaryPosition.x = 0.f;
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+      {
+        cursorInfo.primaryPosition.x = floorf( 0.5f * mVisualModel->mControlSize.width );
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_END:
+      {
+        cursorInfo.primaryPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+        break;
+      }
+    }
+
+    switch( mLayoutEngine.GetVerticalAlignment() )
+    {
+      case LayoutEngine::VERTICAL_ALIGN_TOP:
+      {
+        cursorInfo.primaryPosition.y = 0.f;
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_CENTER:
+      {
+        cursorInfo.primaryPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - cursorInfo.lineHeight ) );
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+      {
+        cursorInfo.primaryPosition.y = mVisualModel->mControlSize.height - cursorInfo.lineHeight;
+        break;
+      }
+    }
 
     // Nothing else to do.
     return;
   }
 
+  // Check if the logical position is the first or the last one of the text.
+  const bool isFirstPosition = 0u == logical;
+  const bool isLastPosition = numberOfCharacters == logical;
+
   // 'logical' is the logical 'cursor' index.
   // Get the next and current logical 'character' index.
   const CharacterIndex nextCharacterIndex = logical;
@@ -1753,7 +1795,7 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index )
   return cursorIndex;
 }
 
-void Controller::Impl::UpdateCursorPosition()
+void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
   if( NULL == mEventData )
@@ -1763,121 +1805,58 @@ void Controller::Impl::UpdateCursorPosition()
     return;
   }
 
-  if( IsShowingPlaceholderText() || ( 0u == mLogicalModel->mText.Count() ) )
-  {
-    // Do not want to use the place-holder text to set the cursor position.
-
-    // Use the line's height of the font's family set to set the cursor's size.
-    // If there is no font's family set, use the default font.
-    // Use the current alignment to place the cursor at the beginning, center or end of the box.
-
-    float lineHeight = 0.f;
-
-    FontId defaultFontId = 0u;
-    if( NULL == mFontDefaults )
-    {
-      TextAbstraction::FontDescription fontDescription;
-      defaultFontId = mFontClient.GetFontId( fontDescription );
-    }
-    else
-    {
-      defaultFontId = mFontDefaults->GetFontId( mFontClient );
-    }
-
-    Text::FontMetrics fontMetrics;
-    mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
-
-    lineHeight = fontMetrics.ascender - fontMetrics.descender;
-
-
-    Vector2 cursorPosition;
+  const Vector2 offset = mEventData->mScrollPosition + ( IsShowingRealText() ? mAlignmentOffset : Vector2::ZERO );
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
 
-    switch( mLayoutEngine.GetHorizontalAlignment() )
-    {
-      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
-      {
-        cursorPosition.x = 0.f;
-        break;
-      }
-      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
-      {
-        cursorPosition.x = floor( 0.5f * mVisualModel->mControlSize.width );
-        break;
-      }
-      case LayoutEngine::HORIZONTAL_ALIGN_END:
-      {
-        cursorPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
-        break;
-      }
-    }
+  // Sets the cursor position.
+  mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.primaryCursorHeight,
+                                       cursorInfo.lineHeight );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
 
-    switch( mLayoutEngine.GetVerticalAlignment() )
-    {
-      case LayoutEngine::VERTICAL_ALIGN_TOP:
-      {
-        cursorPosition.y = 0.f;
-        break;
-      }
-      case LayoutEngine::VERTICAL_ALIGN_CENTER:
-      {
-        cursorPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - lineHeight ) );
-        break;
-      }
-      case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
-      {
-        cursorPosition.y = mVisualModel->mControlSize.height - lineHeight;
-        break;
-      }
-    }
+  // Sets the grab handle position.
+  mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.lineHeight );
 
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         lineHeight,
-                                         lineHeight );
-  }
-  else
+  if( cursorInfo.isSecondaryCursor )
   {
-    CursorInfo cursorInfo;
-    GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                       cursorInfo );
-
-    const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-    const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
-    // Sets the cursor position.
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         cursorInfo.primaryCursorHeight,
-                                         cursorInfo.lineHeight );
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
-
-    // Sets the grab handle position.
-    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
+    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 );
+  }
 
+  // Set which cursors are active according the state.
+  if( ( EventData::EDITING == mEventData->mState )                  ||
+      ( EventData::EDITING_WITH_POPUP == mEventData->mState )       ||
+      ( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) ||
+      ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+  {
     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 );
     }
   }
+  else
+  {
+    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+  }
+
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
 }
 
-void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
+void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
+                                              const CursorInfo& cursorInfo )
 {
   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
       ( RIGHT_SELECTION_HANDLE != handleType ) )
@@ -1885,15 +1864,7 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
     return;
   }
 
-  const bool leftSelectionHandle = LEFT_SELECTION_HANDLE == handleType;
-  const CharacterIndex index = leftSelectionHandle ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
-
-  CursorInfo cursorInfo;
-  GetCursorPosition( index,
-                     cursorInfo );
-
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + mEventData->mScrollPosition + mAlignmentOffset;
 
   // Sets the grab handle position.
   mEventData->mDecorator->SetPosition( handleType,
@@ -1910,6 +1881,7 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
+
   if( actualSize.width > mVisualModel->mControlSize.width )
   {
     const float space = ( actualSize.width - mVisualModel->mControlSize.width ) + mAlignmentOffset.x;
@@ -1943,89 +1915,33 @@ void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
 
 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
 {
-  Vector2 offset;
-  bool updateDecorator = false;
-  if( position.x < 0.f )
-  {
-    offset.x = -position.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
-  }
-  else if( position.x > mVisualModel->mControlSize.width )
+  // position is in actor's coords.
+  const float positionEnd = position.x + ( mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f );
+
+  // Transform the position to decorator coords.
+  const float offset = mEventData->mScrollPosition.x + mAlignmentOffset.x;
+  const float decoratorPositionBegin = position.x + offset;
+  const float decoratorPositionEnd = positionEnd + offset;
+
+  if( decoratorPositionBegin < 0.f )
   {
-    offset.x = mVisualModel->mControlSize.width - position.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
+    mEventData->mScrollPosition.x = -position.x - mAlignmentOffset.x;
   }
-
-  if( updateDecorator && mEventData->mDecorator )
+  else if( decoratorPositionEnd > mVisualModel->mControlSize.width )
   {
-    mEventData->mDecorator->UpdatePositions( offset );
+    mEventData->mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd - mAlignmentOffset.x;
   }
-
-  // TODO : calculate the vertical scroll.
 }
 
-void Controller::Impl::ScrollTextToMatchCursor()
+void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
 {
   // 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() );
-
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
-  // 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->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 );
-  }
-
-  // Set which cursors are active according the state.
-  if( ( EventData::EDITING == mEventData->mState )                  ||
-      ( EventData::EDITING_WITH_POPUP == mEventData->mState )       ||
-      ( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState ) ||
-      ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
-  {
-    if( cursorInfo.isSecondaryCursor )
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
-    }
-    else
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
-    }
-  }
-  else
-  {
-    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
-  }
 }
 
 void Controller::Impl::RequestRelayout()
index 8ada007..f1c4bc4 100644 (file)
@@ -104,7 +104,6 @@ struct EventData
     INACTIVE,
     INTERRUPTED,
     SELECTING,
-    SELECTION_CHANGED,
     EDITING,
     EDITING_WITH_POPUP,
     EDITING_WITH_GRAB_HANDLE,
@@ -390,7 +389,7 @@ struct Controller::Impl
 
   void GetTextFromClipboard( unsigned int itemIndex, std::string& retreivedString );
 
-  void RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd );
+  void RepositionSelectionHandles();
   void RepositionSelectionHandles( float visualX, float visualY );
 
   void SetPopupButtons();
@@ -438,18 +437,23 @@ struct Controller::Impl
   /**
    * @brief Updates the cursor position.
    *
-   * Retrieves the x,y position of the cursor logical position and sets it into the decorator.
+   * Sets the cursor's position into the decorator. It transforms the cursor's position into decorator's coords.
    * It sets the position of the secondary cursor if it's a valid one.
    * Sets which cursors are active.
+   *
+   * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+   *
    */
-  void UpdateCursorPosition();
+  void UpdateCursorPosition( const CursorInfo& cursorInfo );
 
   /**
-   * @brief Updates the position of the given selection handle.
+   * @brief Updates the position of the given selection handle. It transforms the handle's position into decorator's coords.
    *
    * @param[in] handleType One of the selection handles.
+   * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
    */
-  void UpdateSelectionHandle( HandleType handleType );
+  void UpdateSelectionHandle( HandleType handleType,
+                              const CursorInfo& cursorInfo );
 
   /**
    * @biref Clamps the horizontal scrolling to get the control always filled with text.
@@ -482,7 +486,7 @@ struct Controller::Impl
    *
    * This method is called after deleting text.
    */
-  void ScrollTextToMatchCursor();
+  void ScrollTextToMatchCursor( const CursorInfo& cursorInfo);
 
   ControlInterface& mControlInterface;     ///< Reference to the text controller.
   LogicalModelPtr mLogicalModel;           ///< Pointer to the logical model.
index 6b1e31f..07cb7fe 100644 (file)
@@ -89,7 +89,6 @@ void Controller::SetText( const std::string& text )
   {
     // If popup shown then hide it by switching to Editing state
     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
-        ( EventData::SELECTION_CHANGED == mImpl->mEventData->mState )  ||
         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
     {
@@ -725,7 +724,9 @@ bool Controller::Relayout( const Size& size )
     return glyphsRemoved;
   }
 
-  if( size != mImpl->mVisualModel->mControlSize )
+  const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
+
+  if( newSize )
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
 
@@ -751,9 +752,9 @@ bool Controller::Relayout( const Size& size )
   // Do not re-do any operation until something changes.
   mImpl->mOperationsPending = NO_OPERATION;
 
-  // Keep the current offset and alignment as it will be used to update the decorator's positions.
+  // Keep the current offset and alignment as it will be used to update the decorator's positions (if the size changes).
   Vector2 offset;
-  if( mImpl->mEventData )
+  if( newSize && mImpl->mEventData )
   {
     offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
   }
@@ -763,11 +764,14 @@ bool Controller::Relayout( const Size& size )
 
   if( mImpl->mEventData )
   {
-    // If there is a nex size, the scroll position needs to be clamped.
-    mImpl->ClampHorizontalScroll( layoutSize );
+    if( newSize )
+    {
+      // If there is a new size, the scroll position needs to be clamped.
+      mImpl->ClampHorizontalScroll( layoutSize );
 
-    // Update the decorator's positions.
-    mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
+      // Update the decorator's positions is needed if there is a new size.
+      mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
+    }
 
     // Move the cursor, grab handle etc.
     updated = mImpl->ProcessInputEvents() || updated;
@@ -922,11 +926,8 @@ void Controller::TextDeletedEvent()
                                                            REORDER );
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
-  if( 0u == mImpl->mLogicalModel->mText.Count() )
-  {
-    mImpl->mEventData->mUpdateCursorPosition = true;
-  }
-  else
+  mImpl->mEventData->mUpdateCursorPosition = true;
+  if( 0u != mImpl->mLogicalModel->mText.Count() )
   {
     mImpl->mEventData->mScrollAfterDelete = true;
   }
@@ -1179,8 +1180,7 @@ void Controller::CalculateTextAlignment( const Size& size )
     }
     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
     {
-      const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
-      mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
+      mImpl->mAlignmentOffset.x = floorf( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
       break;
     }
     case LayoutEngine::HORIZONTAL_ALIGN_END:
@@ -1200,8 +1200,7 @@ void Controller::CalculateTextAlignment( const Size& size )
     }
     case LayoutEngine::VERTICAL_ALIGN_CENTER:
     {
-      const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
-      mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
+      mImpl->mAlignmentOffset.y = floorf( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
       break;
     }
     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
@@ -1485,8 +1484,7 @@ bool Controller::RemoveSelectedText()
 {
   bool textRemoved( false );
 
-  if ( EventData::SELECTING         == mImpl->mEventData->mState ||
-       EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+  if( EventData::SELECTING == mImpl->mEventData->mState )
   {
     std::string removedString;
     mImpl->RetrieveSelection( removedString, true );
@@ -1623,14 +1621,7 @@ 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 );
-    }
+    mImpl->ChangeState( EventData::SELECTING );
 
     if( selectAll )
     {
@@ -1898,8 +1889,7 @@ bool Controller::BackspaceKeyEvent()
 
   bool removed( false );
 
-  if ( EventData::SELECTING         == mImpl->mEventData->mState ||
-       EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
+  if( EventData::SELECTING == mImpl->mEventData->mState )
   {
     removed = RemoveSelectedText();
   }
index a7b1d49..795e9cf 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 5;
+const unsigned int TOOLKIT_MICRO_VERSION = 6;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index c45b44e..dc32fbd 100644 (file)
@@ -65,11 +65,9 @@ distributing this software or its derivatives.
       "secondary-cursor-color":[0.0,0.72,0.9,1.0],
       "cursor-width":1,
       "selection-highlight-color":[0.75,0.96,1.0,1.0],
-      "grab-handle-image": { "filename":"{DALI_IMAGE_DIR}cursor_handler_center.png" },
-      "selection-handle-image-left" : {"filename":"{DALI_IMAGE_DIR}selection_handle_left.png" },
-      "selection-handle-image-right": {"filename":"{DALI_IMAGE_DIR}selection_handle_right.png" },
-      "selection-handle-marker-image-left":{ "filename":"{DALI_IMAGE_DIR}selection_marker_left.png" },
-      "selection-handle-marker-image-right":{ "filename":"{DALI_IMAGE_DIR}selection_marker_right.png" }
+      "grab-handle-image" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selection-handle-image-left" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selection-handle-image-right": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
     },
 
     "textfield-font-size-0":
diff --git a/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png b/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..a9a2b9e
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png b/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..d9ed8b8
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png b/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..f66b26b
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png differ
index 694e2db..7501b72 100644 (file)
@@ -65,11 +65,9 @@ distributing this software or its derivatives.
       "secondary-cursor-color":[0.0,0.72,0.9,1.0],
       "cursor-width":3,
       "selection-highlight-color":[0.75,0.96,1.0,1.0],
-      "grab-handle-image": { "filename":"{DALI_IMAGE_DIR}cursor_handler_center.png" },
-      "selection-handle-image-left" : {"filename":"{DALI_IMAGE_DIR}selection_handle_left.png" },
-      "selection-handle-image-right": {"filename":"{DALI_IMAGE_DIR}selection_handle_right.png" },
-      "selection-handle-marker-image-left":{ "filename":"{DALI_IMAGE_DIR}selection_marker_left.png" },
-      "selection-handle-marker-image-right":{ "filename":"{DALI_IMAGE_DIR}selection_marker_right.png" }
+      "grab-handle-image" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selection-handle-image-left" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selection-handle-image-right": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
     },
 
     "textfield-font-size-0":
diff --git a/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png b/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..15c937a
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png b/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..149becb
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png b/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..75035bc
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png differ
index 8e49fbe..6c329e9 100644 (file)
@@ -2,3 +2,6 @@
 
 dali_toolkit_style_files =\
     $(toolkit_styles_dir)/*.json
+
+dali_toolkit_style_images =\
+    $(toolkit_style_images_dir)/*.png
index fefb8a3..920c5db 100644 (file)
@@ -39,6 +39,7 @@
    + [Relative To Constraint](@ref constraints-relative-to)
   + [Multi-threading Notes](@ref animation-multi-threading-notes)
   + [Shader Animation](@ref animation-shader)
+  + [Styling](@ref styling)
 
 ### Resources
  + [Resource Image](@ref resource-image)
diff --git a/docs/content/programming-guide/styling.h b/docs/content/programming-guide/styling.h
new file mode 100644 (file)
index 0000000..f1949ca
--- /dev/null
@@ -0,0 +1,62 @@
+/*! \page styling Styling
+ *
+@section styling-controls Styling Controls
+
+DALi Controls can be styled to look and behaviour differently.
+
+There are 2 ways to style a control, 1 is recommended.
+
+1) json markup in one of the style files.
+
+~~~
+      ...
+      "control":
+      {
+        "filename":"{IMAGES}file_name.png"
+      },
+      ...
+~~~
+
+or 2) via code using SetProperty
+
+@code
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+control.SetProperty( Control::BACKGROUND, "file_name.png" );
+@endcode
+
+By setting the properties in the json file and not in code it prevents the need to edit code and recompile if changes required.
+
+In the example above, if the png file needs to be changed, method 1 only requires the json file to be changed and no actual code change.
+
+@section choosing-style-at-build Choosing Style files at build time
+
+When building for a target, a style selector should be specified.
+
+The selectors are resolution biased e.g; 720 and 480.
+
+Below can be added to configure to select a style
+
+@code
+./configure --with-style=480
+@endcode
+
+@code
+./configure --with-style=720
+@endcode
+
+
+or for gbs the below define added to the build command
+
+@code
+--define "dali_style 480x800"
+@endcode
+
+@section resources-for-styling Style specific resources
+
+Each style selector can have resource folders associated with it.
+
+Images for that style should be in their own folder named images.
+
+Common images not specific for a particular style will be in the dali-toolkit common images folder.
+*
+*/
index b80108a..9939f2c 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.1.5
+Version:    1.1.6
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0, BSD-2.0, MIT