Clipping support for TextField 08/36608/17
authorPaul Wisbey <p.wisbey@samsung.com>
Tue, 10 Mar 2015 15:08:41 +0000 (15:08 +0000)
committerPaul Wisbey <p.wisbey@samsung.com>
Thu, 12 Mar 2015 10:44:21 +0000 (10:44 +0000)
Change-Id: Idd630cbf9067007c26344a36610a68f8a40a6b06

dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/text/clipping/text-clipper.cpp [new file with mode: 0644]
dali-toolkit/internal/text/clipping/text-clipper.h [new file with mode: 0644]
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/public-api/controls/text-controls/text-field.h

index d687d51..bfa89f6 100644 (file)
 #include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
 
 // EXTERNAL INCLUDES
+#include <string>
 #include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/common/stage.h>
 #include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
-#include <dali/public-api/common/stage.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
@@ -67,6 +68,7 @@ DALI_PROPERTY_REGISTRATION( TextField, "text",                    STRING,    TEX
 DALI_PROPERTY_REGISTRATION( TextField, "font-family",             STRING,    FONT_FAMILY             )
 DALI_PROPERTY_REGISTRATION( TextField, "font-style",              STRING,    FONT_STYLE              )
 DALI_PROPERTY_REGISTRATION( TextField, "point-size",              FLOAT,     POINT_SIZE              )
+DALI_PROPERTY_REGISTRATION( TextField, "exceed-policy",           INTEGER,   EXCEED_POLICY           )
 DALI_PROPERTY_REGISTRATION( TextField, "cursor-image",            STRING,    CURSOR_IMAGE            )
 DALI_PROPERTY_REGISTRATION( TextField, "primary-cursor-color",    VECTOR4,   PRIMARY_CURSOR_COLOR    )
 DALI_PROPERTY_REGISTRATION( TextField, "secondary-cursor-color",  VECTOR4,   SECONDARY_CURSOR_COLOR  )
@@ -107,7 +109,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
     {
       case Toolkit::TextField::Property::RENDERING_BACKEND:
       {
-        unsigned int backend = value.Get< unsigned int >();
+        int backend = value.Get< int >();
 
         if( impl.mRenderingBackend != backend )
         {
@@ -132,6 +134,53 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::TextField::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          std::string fontFamily = value.Get< std::string >();
+
+          if( impl.mController->GetDefaultFontFamily() != fontFamily )
+          {
+            impl.mController->SetDefaultFontFamily( fontFamily );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::FONT_STYLE:
+      {
+        if( impl.mController )
+        {
+          std::string fontStyle = value.Get< std::string >();
+
+          if( impl.mController->GetDefaultFontStyle() != fontStyle )
+          {
+            impl.mController->SetDefaultFontStyle( fontStyle );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          float pointSize = value.Get< float >();
+
+          if( impl.mController->GetDefaultPointSize() != pointSize /*TODO - epsilon*/ )
+          {
+            impl.mController->SetDefaultPointSize( pointSize );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::EXCEED_POLICY:
+      {
+        impl.mExceedPolicy = value.Get< int >();
+        break;
+      }
       case Toolkit::TextField::Property::CURSOR_IMAGE:
       {
         ResourceImage image = ResourceImage::New( value.Get< std::string >() );
@@ -241,6 +290,11 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
         }
         break;
       }
+      case Toolkit::TextField::Property::EXCEED_POLICY:
+      {
+        value = impl.mExceedPolicy;
+        break;
+      }
       case Toolkit::TextField::Property::CURSOR_IMAGE:
       {
         if( impl.mDecorator )
@@ -350,7 +404,8 @@ float TextField::GetHeightForWidth( float width )
 
 void TextField::OnRelayout( const Vector2& size, ActorSizeContainer& container )
 {
-  if( mController->Relayout( size ) )
+  if( mController->Relayout( size ) ||
+      !mRenderer )
   {
     if( mDecorator )
     {
@@ -362,13 +417,30 @@ void TextField::OnRelayout( const Vector2& size, ActorSizeContainer& container )
       mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
     }
 
+    RenderableActor renderableActor;
     if( mRenderer )
     {
-      Actor renderableActor = mRenderer->Render( mController->GetView() );
+      renderableActor = mRenderer->Render( mController->GetView() );
+    }
+
+    EnableClipping( (Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy), size );
+
+    if( renderableActor != mRenderableActor )
+    {
+      UnparentAndReset( mRenderableActor );
+      mRenderableActor = renderableActor;
+    }
 
-      if( renderableActor )
+    if( mRenderableActor )
+    {
+      // Make sure the actor is parented correctly with/without clipping
+      if( mClipper )
+      {
+        mClipper->GetRootActor().Add( mRenderableActor );
+      }
+      else
       {
-        Self().Add( renderableActor );
+        Self().Add( mRenderableActor );
       }
     }
   }
@@ -396,14 +468,44 @@ void TextField::RequestTextRelayout()
   RelayoutRequest();
 }
 
+void TextField::EnableClipping( bool clipping, const Vector2& size )
+{
+  if( clipping )
+  {
+    // Not worth to created clip actor if width or height is equal to zero.
+    if( size.width > Math::MACHINE_EPSILON_1000 && size.height > Math::MACHINE_EPSILON_1000 )
+    {
+      if( !mClipper )
+      {
+        Actor self = Self();
+
+        mClipper = Clipper::New( size );
+        self.Add( mClipper->GetRootActor() );
+        self.Add( mClipper->GetImageActor() );
+      }
+      else if ( mClipper )
+      {
+        mClipper->Refresh( size );
+      }
+    }
+  }
+  else
+  {
+    // Note - this will automatically remove the root & image actors
+    mClipper.Reset();
+  }
+}
+
 TextField::TextField()
 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_NONE ) ),
-  mRenderingBackend( DEFAULT_RENDERING_BACKEND )
+  mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
+  mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP )
 {
 }
 
 TextField::~TextField()
 {
+  mClipper.Reset();
 }
 
 } // namespace Internal
index 23fa0e9..b94c318 100644 (file)
@@ -21,6 +21,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/text-controls/text-field.h>
+#include <dali-toolkit/internal/text/clipping/text-clipper.h>
 #include <dali-toolkit/internal/text/decorator/text-decorator.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/text-controller.h>
@@ -50,7 +51,8 @@ public:
   // Properties
 
   /**
-   * Called when a property of an object of this type is set.
+   * @brief Called when a property of an object of this type is set.
+   *
    * @param[in] object The object whose property is set.
    * @param[in] index The property index.
    * @param[in] value The new property value.
@@ -58,7 +60,8 @@ public:
   static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
 
   /**
-   * Called to retrieve a property of an object of this type.
+   * @brief Called to retrieve a property of an object of this type.
+   *
    * @param[in] object The object whose property is to be retrieved.
    * @param[in] index The property index.
    * @return The current value of the property.
@@ -105,6 +108,14 @@ private: // From Control
 private: // Implementation
 
   /**
+   * @brief Enable or disable clipping.
+   *
+   * @param[in] clipping True if clipping should be enabled.
+   * @param[in] size The area to clip within.
+   */
+  void EnableClipping( bool clipping, const Vector2& size );
+
+  /**
    * Construct a new TextField.
    */
   TextField();
@@ -125,8 +136,12 @@ private: // Data
   Text::ControllerPtr mController;
   Text::RendererPtr mRenderer;
   Text::DecoratorPtr mDecorator;
+  Text::ClipperPtr mClipper; ///< For EXCEED_POLICY_CLIP
+
+  RenderableActor mRenderableActor;
 
-  unsigned int mRenderingBackend;
+  int mRenderingBackend;
+  int mExceedPolicy;
 };
 
 } // namespace Internal
index 2de2c57..43a600d 100644 (file)
@@ -95,11 +95,11 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
     {
       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
       {
-        unsigned int backend = value.Get< int >();
+        int backend = value.Get< int >();
 
         if( impl.mRenderingBackend != backend )
         {
-          impl.mRenderingBackend = static_cast< unsigned int >( backend );
+          impl.mRenderingBackend = backend;
           impl.mRenderer.Reset();
           impl.RequestTextRelayout();
         }
index de54bf0..c72c9c5 100644 (file)
@@ -48,7 +48,8 @@ public:
   // Properties
 
   /**
-   * Called when a property of an object of this type is set.
+   * @brief Called when a property of an object of this type is set.
+   *
    * @param[in] object The object whose property is set.
    * @param[in] index The property index.
    * @param[in] value The new property value.
@@ -56,7 +57,8 @@ public:
   static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
 
   /**
-   * Called to retrieve a property of an object of this type.
+   * @brief Called to retrieve a property of an object of this type.
+   *
    * @param[in] object The object whose property is to be retrieved.
    * @param[in] index The property index.
    * @return The current value of the property.
@@ -114,7 +116,7 @@ private: // Data
   Text::RendererPtr mRenderer;
   RenderableActor mRenderableActor;
 
-  unsigned int mRenderingBackend;
+  int mRenderingBackend;
 };
 
 } // namespace Internal
index e7a40ec..e3f1495 100644 (file)
@@ -75,6 +75,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/styling/style-manager-impl.cpp \
    $(toolkit_src_dir)/text/bidirectional-support.cpp \
    $(toolkit_src_dir)/text/character-set-conversion.cpp \
+   $(toolkit_src_dir)/text/clipping/text-clipper.cpp \
    $(toolkit_src_dir)/text/logical-model.cpp \
    $(toolkit_src_dir)/text/multi-language-support.cpp \
    $(toolkit_src_dir)/text/segmentation.cpp \
diff --git a/dali-toolkit/internal/text/clipping/text-clipper.cpp b/dali-toolkit/internal/text/clipping/text-clipper.cpp
new file mode 100644 (file)
index 0000000..1b3a38c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/clipping/text-clipper.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+
+// Currently on desktop machines 2k x 2k is the maximum frame buffer size, on target is 4k x 4k.
+const float MAX_OFFSCREEN_RENDERING_SIZE = 2048.f;
+
+} // namespace
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+ClipperPtr Clipper::New( const Vector2& size )
+{
+  ClipperPtr clipper( new Clipper() );
+
+  // Second-phase init
+  clipper->Initialize( size );
+
+  return clipper;
+}
+
+Actor Clipper::GetRootActor() const
+{
+  return mOffscreenRootActor;
+}
+
+ImageActor Clipper::GetImageActor() const
+{
+  return mImageActor;
+}
+
+void Clipper::Refresh( const Vector2& size )
+{
+  const Size offscreenSize( std::min( MAX_OFFSCREEN_RENDERING_SIZE, size.width ),
+                            std::min( MAX_OFFSCREEN_RENDERING_SIZE, size.height ) );
+
+  const bool sizeChanged = offscreenSize != mCurrentOffscreenSize;
+
+  if( sizeChanged )
+  {
+    // Reconfigure camera for current size.
+    mOffscreenCameraActor.SetOrthographicProjection( offscreenSize );
+
+    // Recreate frame buffer for offscreen rendering when the size changes.
+    FrameBufferImage frameBufferImage = FrameBufferImage::New( offscreenSize.width,
+                                                               offscreenSize.height,
+                                                               Pixel::RGBA8888 );
+    mImageActor.SetImage( frameBufferImage );
+    mRenderTask.SetTargetFrameBuffer( frameBufferImage );
+
+    // Stores current size to avoid create new Dali resources if text changes.
+    mCurrentOffscreenSize = offscreenSize;
+  }
+
+  mRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
+}
+
+void Clipper::Initialize( const Vector2& size )
+{
+  const Size offscreenSize( std::min( MAX_OFFSCREEN_RENDERING_SIZE, size.width ),
+                            std::min( MAX_OFFSCREEN_RENDERING_SIZE, size.height ) );
+
+  // Create a root actor and an image actor for offscreen rendering.
+  mOffscreenRootActor = Layer::New();
+  mOffscreenRootActor.SetColorMode( USE_OWN_COLOR );
+  mOffscreenRootActor.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
+  mOffscreenRootActor.SetInheritRotation( false );
+  mOffscreenRootActor.SetInheritScale( false );
+  mOffscreenRootActor.SetDepthTestDisabled( true );
+  mOffscreenRootActor.SetSize( offscreenSize );
+  mOffscreenRootActor.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  mImageActor = ImageActor::New();
+  mImageActor.SetAnchorPoint( ParentOrigin::CENTER );
+  mImageActor.SetParentOrigin( ParentOrigin::CENTER );
+  mImageActor.SetBlendFunc( BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA,
+                            BlendingFactor::ONE, BlendingFactor::ONE );
+  mImageActor.SetScale( Vector3( 1.0f, -1.0f, 1.0f ) );
+  mImageActor.SetSize( offscreenSize );
+
+  // Creates a new camera actor.
+  mOffscreenCameraActor = CameraActor::New();
+  mOffscreenCameraActor.SetParentOrigin( ParentOrigin::CENTER );
+  mOffscreenCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+  mOffscreenCameraActor.SetRotation(Degree(180.f), Vector3::YAXIS);
+  mOffscreenCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Inherits position from the offscreen root actor.
+  mOffscreenCameraActor.SetOrthographicProjection( offscreenSize );
+  mOffscreenRootActor.Add( mOffscreenCameraActor ); // camera to shoot the offscreen text
+
+  // Creates a new render task.
+  mRenderTask = Stage::GetCurrent().GetRenderTaskList().CreateTask();
+  mRenderTask.SetSourceActor( mOffscreenRootActor );
+  mRenderTask.SetInputEnabled( false );
+  mRenderTask.SetClearColor( Color::TRANSPARENT );
+  mRenderTask.SetClearEnabled( true );
+  mRenderTask.SetExclusive( true );
+  mRenderTask.SetCameraActor( mOffscreenCameraActor );
+
+  // Creates a frame buffer for offscreen rendering
+  FrameBufferImage frameBufferImage = FrameBufferImage::New( offscreenSize.width,
+                                                             offscreenSize.height,
+                                                             Pixel::RGBA8888 );
+  mImageActor.SetImage( frameBufferImage );
+  mRenderTask.SetTargetFrameBuffer( frameBufferImage );
+
+  // Stores current size to avoid create new Dali resources if text changes.
+  mCurrentOffscreenSize = offscreenSize;
+}
+
+Clipper::Clipper()
+{
+}
+
+Clipper::~Clipper()
+{
+  if( Stage::IsInstalled() )
+  {
+    UnparentAndReset( mOffscreenRootActor );
+    UnparentAndReset( mImageActor );
+
+    Stage::GetCurrent().GetRenderTaskList().RemoveTask( mRenderTask );
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/clipping/text-clipper.h b/dali-toolkit/internal/text/clipping/text-clipper.h
new file mode 100644 (file)
index 0000000..d435c86
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __DALI_TOOLKIT_INTERNAL_TEXT_CLIPPER_H__
+#define __DALI_TOOLKIT_INTERNAL_TEXT_CLIPPER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/actors/image-actor.h>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/render-tasks/render-task.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class Clipper;
+typedef IntrusivePtr<Clipper> ClipperPtr;
+
+/**
+ * @brief A helper class for clipping actors using a FrameBufferImage.
+ */
+class Clipper : public RefObject
+{
+public:
+
+  /**
+   * @brief Create a clipper.
+   *
+   * @param[in] size The size of the clipping region.
+   */
+  static ClipperPtr New( const Vector2& size );
+
+  /**
+   * @brief Children added to this actor will be clipped with the specified region.
+   *
+   * @note This is done by rendering to a FrameBufferImage which must then be displayed; see also GetImageActor().
+   * @return The root actor.
+   */
+  Actor GetRootActor() const;
+
+  /**
+   * @brief This actor will display the resulting FrameBufferImage.
+   *
+   * @return The image actor.
+   */
+  ImageActor GetImageActor() const;
+
+  /**
+   * @brief Refresh the contents of the FrameBufferImage.
+   *
+   * @param[in] size The size of the clipping region.
+   */
+  void Refresh( const Vector2& size );
+
+private: // Implementation
+
+  /**
+   * @brief Second-phase init
+   *
+   * @param[in] size The size of the clipping region.
+   */
+  void Initialize( const Vector2& size );
+
+  /**
+   * Construct a new Clipper.
+   */
+  Clipper();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Clipper();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  Clipper(const Clipper&);
+  Clipper& operator=(const Clipper& rhs);
+
+private: // Data
+
+  Layer mOffscreenRootActor;
+  CameraActor mOffscreenCameraActor;
+  ImageActor mImageActor;
+  RenderTask mRenderTask;
+  Vector2 mCurrentOffscreenSize;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_INTERNAL_TEXT_CLIPPER_H__
index 41b12c3..df66c5f 100644 (file)
@@ -267,7 +267,7 @@ struct Decorator::Impl : public ConnectionTracker
 
 
   Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
-  : mParent(parent),
+  : mTextControlParent(parent),
     mObserver(observer),
     mActiveCursor(ACTIVE_CURSOR_NONE),
     mActiveGrabHandle(false),
@@ -288,14 +288,25 @@ struct Decorator::Impl : public ConnectionTracker
    */
   void Relayout( const Vector2& size )
   {
-    SetCursors();
+    // TODO - Remove this if nothing is active
+    CreateActiveLayer();
+
+    // Show or hide the cursors
+    CreateCursors();
+    if( mPrimaryCursor )
+    {
+      mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y );
+    }
+    if( mSecondaryCursor )
+    {
+      mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].x, mCursor[SECONDARY_CURSOR].y );
+    }
 
     // Show or hide the grab handle
     if( mActiveGrabHandle )
     {
       SetupTouchEvents();
 
-      CreateActiveLayer();
       CreateGrabHandle();
 
       mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y + mCursor[PRIMARY_CURSOR].height );
@@ -310,7 +321,6 @@ struct Decorator::Impl : public ConnectionTracker
     {
       SetupTouchEvents();
 
-      CreateActiveLayer();
       CreateSelectionHandles();
 
       SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
@@ -350,45 +360,39 @@ struct Decorator::Impl : public ConnectionTracker
   }
 
   // Add or Remove cursor(s) from parent
-  void SetCursors()
+  void CreateCursors()
   {
-    Actor parent = mParent.Self();
-    /* Create Primary and or Secondary Cursor(s) if active and add to parent */
-    if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY )
+    if( mActiveCursor == ACTIVE_CURSOR_NONE )
     {
-      if ( !mPrimaryCursor )
-      {
-        CreateCursor( mPrimaryCursor );
-#ifdef DECORATOR_DEBUG
-        mPrimaryCursor.SetName( "PrimaryCursorActor" );
-#endif
-        parent.Add( mPrimaryCursor);
-      }
-
-      mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].x, mCursor[PRIMARY_CURSOR].y );
+      UnparentAndReset( mPrimaryCursor );
+      UnparentAndReset( mSecondaryCursor );
     }
-    else if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
+    else
     {
-      if ( !mSecondaryCursor )
+      /* Create Primary and or Secondary Cursor(s) if active and add to parent */
+      if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ||
+           mActiveCursor == ACTIVE_CURSOR_BOTH )
       {
-        CreateCursor( mSecondaryCursor );
+        if ( !mPrimaryCursor )
+        {
+          CreateCursor( mPrimaryCursor );
 #ifdef DECORATOR_DEBUG
-        mSecondaryCursor.SetName( "SecondaryCursorActor" );
+          mPrimaryCursor.SetName( "PrimaryCursorActor" );
 #endif
-        parent.Add( mSecondaryCursor);
-      }
-    }
-    else
-    {
-      /* ACTIVE_CURSOR_NONE so unparent cursors*/
-      if ( mPrimaryCursor )
-      {
-        UnparentAndReset( mPrimaryCursor );
+          mActiveLayer.Add( mPrimaryCursor);
+        }
       }
 
-      if ( mSecondaryCursor )
+      if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
       {
-        UnparentAndReset( mSecondaryCursor );
+        if ( !mSecondaryCursor )
+        {
+          CreateCursor( mSecondaryCursor );
+#ifdef DECORATOR_DEBUG
+          mSecondaryCursor.SetName( "SecondaryCursorActor" );
+#endif
+          mActiveLayer.Add( mSecondaryCursor);
+        }
       }
     }
   }
@@ -396,13 +400,12 @@ struct Decorator::Impl : public ConnectionTracker
   bool OnCursorBlinkTimerTick()
   {
     // Cursor blinking
-    if ( ACTIVE_CURSOR_PRIMARY )
+    if ( mPrimaryCursor )
     {
       mPrimaryCursor.SetVisible( mCursorBlinkStatus );
     }
-    else if ( ACTIVE_CURSOR_BOTH )
+    if ( mSecondaryCursor )
     {
-      mPrimaryCursor.SetVisible( mCursorBlinkStatus );
       mSecondaryCursor.SetVisible( mCursorBlinkStatus );
     }
 
@@ -430,7 +433,7 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( !mActiveLayer )
     {
-      Actor parent = mParent.Self();
+      Actor parent = mTextControlParent.Self();
 
       mActiveLayer = Layer::New();
 #ifdef DECORATOR_DEBUG
@@ -870,8 +873,8 @@ struct Decorator::Impl : public ConnectionTracker
       CreateBackground( mCopyPastePopup );
       AddPopupOptions( true, true );
       SetUpPopup( mCopyPastePopup.mRoot, mCopyPastePopup.mVisiblePopUpSize );
-      Actor parent = mParent.Self();
-      parent.Add( mCopyPastePopup.mRoot );
+      Actor textControl = mTextControlParent.Self();
+      textControl.Add( mCopyPastePopup.mRoot );
     }
   }
 
@@ -885,7 +888,7 @@ struct Decorator::Impl : public ConnectionTracker
     }
   }
 
-  Internal::Control& mParent;
+  Internal::Control& mTextControlParent;
   Observer& mObserver;
 
   Layer mActiveLayer; // Layer for active handles and alike that ensures they are above all else.
index 821b35c..5b35407 100644 (file)
@@ -61,6 +61,7 @@ public:
       FONT_FAMILY,                              ///< name "font-family",             The requested font family,                                                type STRING
       FONT_STYLE,                               ///< name "font-style",              The requested font style e.g. Regular/Italic,                             type STRING
       POINT_SIZE,                               ///< name "point-size",              The size of font in points,                                               type FLOAT
+      EXCEED_POLICY,                            ///< name "exceed-policy"            Specifies how the text is truncated when it does not fit,                 type INT
       CURSOR_IMAGE,                             ///< name "cursor-image",            The image to display for cursors,                                         type STRING
       PRIMARY_CURSOR_COLOR,                     ///< name "primary-cursor-color",    The color to apply to the primary cursor,                                 type VECTOR4
       SECONDARY_CURSOR_COLOR,                   ///< name "secondary-cursor-color",  The color to apply to the secondary cursor,                               type VECTOR4
@@ -73,6 +74,17 @@ public:
   };
 
   /**
+   * @brief Specifies how the text is truncated when it does not fit
+   *
+   * The default value is \e EXCEED_POLICY_CLIP.
+   */
+  enum ExceedPolicy
+  {
+    EXCEED_POLICY_ORIGINAL,        ///< The text will be display at original size, and may exceed the TextField boundary.
+    EXCEED_POLICY_CLIP             ///< The end of text will be clipped to fit within the TextField.
+  };
+
+  /**
    * Create the TextField control.
    * @return A handle to the TextField control.
    */