[dali_1.0.44] Merge branch 'devel/master' 50/41150/1
authorTom Robinson <tom.robinson@samsung.com>
Thu, 11 Jun 2015 09:46:31 +0000 (10:46 +0100)
committerTom Robinson <tom.robinson@samsung.com>
Thu, 11 Jun 2015 09:46:31 +0000 (10:46 +0100)
Change-Id: I98599419300e9a3fac15ead009f6ee118d780946

35 files changed:
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
build/tizen/docs/dali_doxygen.css
dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp
dali-toolkit/internal/atlas-manager/atlas-manager-impl.h
dali-toolkit/internal/atlas-manager/atlas-manager.cpp
dali-toolkit/internal/atlas-manager/atlas-manager.h
dali-toolkit/internal/controls/text-controls/text-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/focus-manager/accessibility-focus-manager-impl.cpp
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/text-control-interface.h
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/text-controls/text-field.cpp
dali-toolkit/public-api/controls/text-controls/text-field.h
dali-toolkit/public-api/dali-toolkit-version.cpp
docs/content/images/item-view/depth.png [new file with mode: 0644]
docs/content/images/item-view/grid.png [new file with mode: 0644]
docs/content/images/item-view/spiral.png [new file with mode: 0644]
docs/content/main.md
docs/content/programming-guide/item-view.h [deleted file]
docs/content/shared-javascript-and-cpp-documentation/item-view.md [new file with mode: 0644]
packaging/dali-toolkit.spec

index a8be49e..d19b3a1 100644 (file)
@@ -55,11 +55,19 @@ const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decoration-bounding-b
 const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT    = "horizontal-alignment";
 const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT      = "vertical-alignment";
 
+static bool gTextChangedCallBackCalled;
 static bool gMaxCharactersCallBackCalled;
 
+static void TestTextChangedCallback( TextField control )
+{
+  tet_infoline(" TestTextChangedCallback");
+
+  gTextChangedCallBackCalled = true;
+}
+
 static void TestMaxLengthReachedCallback( TextField control )
 {
-  tet_infoline(" TestMaxLengthReachedCallbackCallback");
+  tet_infoline(" TestMaxLengthReachedCallback");
 
   gMaxCharactersCallBackCalled = true;
 }
@@ -332,6 +340,60 @@ int utcDaliTextFieldAtlasRenderP(void)
   END_TEST;
 }
 
+// Positive test for the text-changed signal.
+int utcDaliTextFieldTextChangedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add(field);
+
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::TEXT, "ABC" );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  application.SendNotification();
+
+  field.SetKeyInputFocus();
+
+  Dali::Integration::KeyEvent keyevent;
+  keyevent.keyName = "D";
+  keyevent.keyString = "D";
+  keyevent.keyCode = 0;
+  keyevent.keyModifier = 0;
+  keyevent.time = 0;
+  keyevent.state = Integration::KeyEvent::Down;
+
+  gTextChangedCallBackCalled = false;
+  application.ProcessEvent( keyevent );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
+// Negative test for the text-changed signal.
+int utcDaliTextFieldTextChangedN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedN");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add(field);
+
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT
+  DALI_TEST_CHECK( ! gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
 // Positive test for Max Characters reached signal.
 int utcDaliTextFieldMaxCharactersReachedP(void)
 {
index 4b68ddf..223b8ef 100644 (file)
@@ -1,7 +1,8 @@
 .image
 {
    text-align: left;
-   margin-left: 50px;
+   margin-left: 20px;
+   margin-right: 20px;
 }
 
 div.image img {
index 853c0ae..266e8b9 100644 (file)
@@ -651,7 +651,8 @@ void AtlasManager::UploadImage( const BufferImage& image,
 
 void AtlasManager::GenerateMeshData( ImageId id,
                                      const Vector2& position,
-                                     MeshData& meshData )
+                                     MeshData& meshData,
+                                     bool addReference )
 {
   // Read the atlas Id to use for this image
   SizeType imageId = id - 1u;
@@ -672,8 +673,11 @@ void AtlasManager::GenerateMeshData( ImageId id,
 
   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
 
-  // Mesh created so increase the reference count
-  mImageList[ imageId ].mCount++;
+  // Mesh created so increase the reference count, if we're asked to
+  if ( addReference )
+  {
+    mImageList[ imageId ].mCount++;
+  }
 }
 
 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
@@ -826,7 +830,6 @@ void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
   metrics.mTextureMemoryUsed = textureMemoryUsed;
 }
 
-
 } // namespace Internal
 
 } // namespace Toolkit
index ef078f8..7c8470d 100644 (file)
@@ -111,7 +111,8 @@ public:
    */
   void GenerateMeshData( ImageId id,
                          const Vector2& position,
-                         MeshData& mesh );
+                         MeshData& mesh,
+                         bool addReference );
 
   /**
    * @copydoc Toolkit::AtlasManager::StitchMesh
index e46eb1d..6773416 100644 (file)
@@ -69,11 +69,13 @@ bool AtlasManager::Remove( ImageId id )
 
 void AtlasManager::GenerateMeshData( ImageId id,
                                      const Vector2& position,
-                                     MeshData& meshData)
+                                     MeshData& meshData,
+                                     bool addReference )
 {
   GetImplementation(*this).GenerateMeshData( id,
                                              position,
-                                             meshData );
+                                             meshData,
+                                             addReference );
 }
 
 void AtlasManager::StitchMesh( MeshData& first,
index 2bf79f0..2330647 100644 (file)
@@ -274,10 +274,12 @@ public:
    * @param[in] id Image Id returned in the AtlasSlot from the add operation
    * @param[in] position position of the resulting mesh in model space
    * @param[out] mesh Mesh Data Object to populate with mesh data
+   * @param[in] addReference Whether to increase the internal reference count for image or not
    */
   void GenerateMeshData( ImageId id,
                          const Vector2& position,
-                         MeshData& mesh );
+                         MeshData& mesh,
+                         bool addReference = true );
 
   /**
    * @brief Append second mesh to the first mesh
index 11ec5c2..43de0d9 100644 (file)
@@ -119,6 +119,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-highlight-color",
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "decoration-bounding-box",              RECTANGLE, DECORATION_BOUNDING_BOX              )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "input-method-settings",                MAP,       INPUT_METHOD_SETTINGS                )
 
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "text-changed",       SIGNAL_TEXT_CHANGED )
 DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "max-length-reached", SIGNAL_MAX_LENGTH_REACHED )
 
 DALI_TYPE_REGISTRATION_END()
@@ -825,7 +826,11 @@ bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface*
   bool connected( true );
   Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
 
-  if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_CHANGED ) )
+  {
+    field.TextChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
   {
     field.MaxLengthReachedSignal().Connect( tracker, functor );
   }
@@ -838,6 +843,11 @@ bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface*
   return connected;
 }
 
+Toolkit::TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return mTextChangedSignal;
+}
+
 Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
 {
   return mMaxLengthReachedSignal;
@@ -849,7 +859,7 @@ void TextField::OnInitialize()
 
   mController = Text::Controller::New( *this );
 
-  mDecorator = Text::Decorator::New( *this, *mController );
+  mDecorator = Text::Decorator::New( *mController );
 
   mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
 
@@ -1021,10 +1031,12 @@ bool TextField::OnKeyEvent( const KeyEvent& event )
   return mController->KeyEvent( event );
 }
 
-ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+void TextField::AddDecoration( Actor& actor )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
-  return mController->OnImfEvent( imfManager, imfEvent );
+  if( actor )
+  {
+    Self().Add( actor );
+  }
 }
 
 void TextField::RequestTextRelayout()
@@ -1032,12 +1044,24 @@ void TextField::RequestTextRelayout()
   RelayoutRequest();
 }
 
+void TextField::TextChanged()
+{
+  Dali::Toolkit::TextField handle( GetOwner() );
+  mTextChangedSignal.Emit( handle );
+}
+
 void TextField::MaxLengthReached()
 {
   Dali::Toolkit::TextField handle( GetOwner() );
   mMaxLengthReachedSignal.Emit( handle );
 }
 
+ImfManager::ImfCallbackData TextField::OnImfEvent( Dali::ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnImfEvent %p eventName %d\n", mController.Get(), imfEvent.eventName );
+  return mController->OnImfEvent( imfManager, imfEvent );
+}
+
 void TextField::EnableClipping( bool clipping, const Vector2& size )
 {
   if( clipping )
index 5e0df24..0e53053 100644 (file)
@@ -80,6 +80,11 @@ public:
   static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
 
   /**
+   * @copydoc TextField::TextChangedSignal()
+   */
+  Toolkit::TextField::TextChangedSignalType&  TextChangedSignal();
+
+  /**
    * @copydoc TextField::MaxLengthReachedSignal()
    */
   Toolkit::TextField::MaxLengthReachedSignalType&  MaxLengthReachedSignal();
@@ -137,9 +142,9 @@ private: // From Control
   virtual bool OnKeyEvent(const KeyEvent& event);
 
   /**
-   * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent)
+   * @copydoc Text::ControlInterface::AddDecoration()
    */
-  ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
+  virtual void AddDecoration( Actor& actor );
 
   /**
    * @copydoc Text::ControlInterface::RequestTextRelayout()
@@ -147,10 +152,20 @@ private: // From Control
   virtual void RequestTextRelayout();
 
   /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
    * @copydoc Text::ControlInterface::MaxLengthReached()
    */
   virtual void MaxLengthReached();
 
+  /**
+   * @copydoc Dali::Toolkit::Text::Controller::(ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent)
+   */
+  ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
+
 private: // Implementation
 
   /**
@@ -193,6 +208,7 @@ private: // Implementation
 private: // Data
 
   // Signals
+  Toolkit::TextField::TextChangedSignalType mTextChangedSignal;
   Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal;
 
   Text::ControllerPtr mController;
index 35761df..854ddbf 100644 (file)
@@ -489,11 +489,21 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
   }
 }
 
+void TextLabel::AddDecoration( Actor& actor )
+{
+  // TextLabel does not show decorations
+}
+
 void TextLabel::RequestTextRelayout()
 {
   RelayoutRequest();
 }
 
+void TextLabel::TextChanged()
+{
+  // TextLabel does not provide a signal for this
+}
+
 void TextLabel::MaxLengthReached()
 {
   // Pure Virtual from TextController Interface, only needed when inputting text
index 3e0fd35..12dc56e 100644 (file)
@@ -93,11 +93,21 @@ private: // From Control
   virtual float GetHeightForWidth( float width );
 
   /**
+   * @copydoc Text::ControlInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor );
+
+  /**
    * @copydoc Text::ControlInterface::RequestTextRelayout()
    */
   virtual void RequestTextRelayout();
 
   /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
    * @copydoc Text::ControlInterface::MaxLengthReached()
    */
   virtual void MaxLengthReached();
index 728bd42..0be65d3 100644 (file)
@@ -190,7 +190,7 @@ void AccessibilityFocusManager::SetFocusOrder(Actor actor, const unsigned int or
     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
     if(propertyActorFocusable == Property::INVALID_INDEX)
     {
-      propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
+      propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE );
     }
 
     if(order == 0)
@@ -511,7 +511,7 @@ void AccessibilityFocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
     if(propertyIsFocusGroup == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
+      actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
     }
     else
     {
@@ -654,7 +654,7 @@ void AccessibilityFocusManager::SetFocusable(Actor actor, bool focusable)
     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
     if(propertyActorFocusable == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
+      actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
     }
     else
     {
index 19573e8..5be38ac 100644 (file)
@@ -397,7 +397,7 @@ void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
     if(propertyIsFocusGroup == Property::INVALID_INDEX)
     {
-      actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup);
+      actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE );
     }
     else
     {
index e92866b..2961c52 100644 (file)
@@ -209,9 +209,8 @@ struct Decorator::Impl : public ConnectionTracker
     bool flipped : 1;
   };
 
-  Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
-  : mTextControlParent( parent ),
-    mObserver( observer ),
+  Impl( ControllerInterface& controller )
+  : mController( controller ),
     mBoundingBox( Rect<int>() ),
     mHighlightColor( LIGHT_BLUE ),
     mActiveCursor( ACTIVE_CURSOR_NONE ),
@@ -474,8 +473,6 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( !mActiveLayer )
     {
-      Actor parent = mTextControlParent.Self();
-
       mActiveLayer = Layer::New();
 #ifdef DECORATOR_DEBUG
       mActiveLayer.SetName ( "ActiveLayerActor" );
@@ -485,7 +482,7 @@ struct Decorator::Impl : public ConnectionTracker
       mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
       mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
 
-      parent.Add( mActiveLayer );
+      mController.AddDecoration( mActiveLayer );
     }
 
     mActiveLayer.RaiseToTop();
@@ -625,8 +622,7 @@ struct Decorator::Impl : public ConnectionTracker
       mHighlightMeshActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
       mHighlightMeshActor.SetPosition( 0.0f, 0.0f, DISPLAYED_HIGHLIGHT_Z_OFFSET );
 
-      Actor parent = mTextControlParent.Self();
-      parent.Add( mHighlightMeshActor );
+      mController.AddDecoration( mHighlightMeshActor );
     }
   }
 
@@ -746,13 +742,16 @@ struct Decorator::Impl : public ConnectionTracker
     if( Gesture::Started    == gesture.state ||
         Gesture::Continuing == gesture.state )
     {
+      Vector2 targetSize;
+      mController.GetTargetSize( targetSize );
+
       if( x < mScrollThreshold )
       {
         mScrollDirection = SCROLL_RIGHT;
         mHandleScrolling = type;
         StartScrollTimer();
       }
-      else if( x > mTextControlParent.Self().GetTargetSize().width - mScrollThreshold )
+      else if( x > targetSize.width - mScrollThreshold )
       {
         mScrollDirection = SCROLL_LEFT;
         mHandleScrolling = type;
@@ -762,7 +761,7 @@ struct Decorator::Impl : public ConnectionTracker
       {
         mHandleScrolling = HANDLE_TYPE_COUNT;
         StopScrollTimer();
-        mObserver.HandleEvent( type, HANDLE_PRESSED, x, y );
+        mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
       }
     }
     else if( Gesture::Finished  == gesture.state ||
@@ -772,11 +771,11 @@ struct Decorator::Impl : public ConnectionTracker
       {
         mHandleScrolling = HANDLE_TYPE_COUNT;
         StopScrollTimer();
-        mObserver.HandleEvent( type, HANDLE_STOP_SCROLLING, x, y );
+        mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
       }
       else
       {
-        mObserver.HandleEvent( type, HANDLE_RELEASED, x, y );
+        mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
       }
       handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
     }
@@ -992,17 +991,16 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( HANDLE_TYPE_COUNT != mHandleScrolling )
     {
-      mObserver.HandleEvent( mHandleScrolling,
-                             HANDLE_SCROLLING,
-                             mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
-                             0.f );
+      mController.DecorationEvent( mHandleScrolling,
+                               HANDLE_SCROLLING,
+                               mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
+                               0.f );
     }
 
     return true;
   }
 
-  Internal::Control&  mTextControlParent;
-  Observer&           mObserver;
+  ControllerInterface& mController;
 
   TapGestureDetector  mTapDetector;
   PanGestureDetector  mPanGestureDetector;
@@ -1044,9 +1042,9 @@ struct Decorator::Impl : public ConnectionTracker
   bool                mSecondaryCursorVisible : 1; ///< Whether the secondary cursor is visible.
 };
 
-DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
+DecoratorPtr Decorator::New( ControllerInterface& controller )
 {
-  return DecoratorPtr( new Decorator(parent, observer) );
+  return DecoratorPtr( new Decorator(controller) );
 }
 
 void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
@@ -1255,10 +1253,10 @@ Decorator::~Decorator()
   delete mImpl;
 }
 
-Decorator::Decorator( Dali::Toolkit::Internal::Control& parent, Observer& observer )
+Decorator::Decorator( ControllerInterface& controller )
 : mImpl( NULL )
 {
-  mImpl = new Decorator::Impl( parent, observer );
+  mImpl = new Decorator::Impl( controller );
 }
 
 } // namespace Text
index e341e2b..b271b7b 100644 (file)
@@ -27,6 +27,7 @@
 namespace Dali
 {
 
+class Actor;
 class Image;
 class Vector2;
 class Vector4;
@@ -98,26 +99,40 @@ enum HandleType
  *
  * Selection handles will be flipped around to ensure they do not exceed the Decoration Bounding Box. ( Stay visible ).
  *
- * Decorator components forward input events to a controller class through an observer interface.
+ * Decorator components forward input events to a controller class through an interface.
  * The controller is responsible for selecting which components are active.
  */
 class Decorator : public RefObject
 {
 public:
 
-  class Observer
+  class ControllerInterface
   {
   public:
 
     /**
      * @brief Constructor.
      */
-    Observer() {};
+    ControllerInterface() {};
 
     /**
      * @brief Virtual destructor.
      */
-    virtual ~Observer() {};
+    virtual ~ControllerInterface() {};
+
+    /**
+     * @brief An input event from one of the handles.
+     *
+     * @param[out] targetSize The Size of the UI control the decorator is adding it's decorations to.
+     */
+    virtual void GetTargetSize( Vector2& targetSize ) = 0;
+
+    /**
+     * @brief Add a decoration to the parent UI control.
+     *
+     * @param[in] decoration The actor displaying a decoration.
+     */
+    virtual void AddDecoration( Actor& actor ) = 0;
 
     /**
      * @brief An input event from one of the handles.
@@ -127,17 +142,16 @@ public:
      * @param[in] x The x position relative to the top-left of the parent control.
      * @param[in] y The y position relative to the top-left of the parent control.
      */
-    virtual void HandleEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
+    virtual void DecorationEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
   };
 
   /**
    * @brief Create a new instance of a Decorator.
    *
-   * @param[in] parent Decorations will be added to this parent control.
-   * @param[in] observer A class which receives input events from Decorator components.
+   * @param[in] controller The controller which receives input events from Decorator components.
    * @return A pointer to a new Decorator.
    */
-  static DecoratorPtr New( Dali::Toolkit::Internal::Control& parent, Observer& observer );
+  static DecoratorPtr New( ControllerInterface& controller );
 
   /**
    * @brief Set the bounding box which handles, popup and similar decorations will not exceed.
@@ -440,10 +454,9 @@ private:
 
   /**
    * @brief Private constructor.
-   * @param[in] parent Decorations will be added to this parent control.
-   * @param[in] observer A class which receives input events from Decorator components.
+   * @param[in] controller The controller which receives input events from Decorator components.
    */
-  Decorator(Dali::Toolkit::Internal::Control& parent, Observer& observer );
+  Decorator( ControllerInterface& controller );
 
   // Undefined
   Decorator( const Decorator& handle );
index 734b82a..d7fde4e 100644 (file)
@@ -40,6 +40,18 @@ AtlasGlyphManager::AtlasGlyphManager()
 
 AtlasGlyphManager::~AtlasGlyphManager()
 {
+  // Clear up any remaining references
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
+  {
+    for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+          glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
+          ++glyphRecordEntryIt )
+    {
+      mAtlasManager.Remove( glyphRecordEntryIt->mImageId );
+    }
+  }
 }
 
 AtlasGlyphManagerPtr AtlasGlyphManager::New()
@@ -48,17 +60,39 @@ AtlasGlyphManagerPtr AtlasGlyphManager::New()
   return internal;
 }
 
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+                             const Text::GlyphInfo& glyph,
                              const BufferImage& bitmap,
                              Dali::Toolkit::AtlasManager::AtlasSlot& slot )
 {
-  GlyphRecord record;
-  record.mFontId = glyph.fontId;
-  record.mIndex = glyph.index;
-
   mAtlasManager.Add( bitmap, slot );
+
+  GlyphRecordEntry record;
+  record.mIndex = glyph.index;
   record.mImageId = slot.mImageId;
-  mGlyphRecords.PushBack( record );
+  record.mCount = 1;
+
+  // Have glyph records been created for this fontId ?
+  bool foundGlyph = false;
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end(); ++fontGlyphRecordIt )
+  {
+    if ( fontGlyphRecordIt->mFontId == fontId )
+    {
+      fontGlyphRecordIt->mGlyphRecords.PushBack( record );
+      foundGlyph = true;
+      break;
+    }
+  }
+
+  if ( !foundGlyph )
+  {
+    // We need to add a new font entry
+    FontGlyphRecord fontGlyphRecord;
+    fontGlyphRecord.mFontId = fontId;
+    fontGlyphRecord.mGlyphRecords.PushBack( record );
+    mFontGlyphRecords.push_back( fontGlyphRecord );
+  }
 
 #ifdef DISPLAY_ATLAS
   {
@@ -83,7 +117,8 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
                                           const Vector2& position,
                                           MeshData& meshData )
 {
-  mAtlasManager.GenerateMeshData( imageId, position, meshData );
+  // Generate mesh data and tell Atlas Manager not to handle reference counting ( we'll do it )
+  mAtlasManager.GenerateMeshData( imageId, position, meshData, false );
 }
 
 void AtlasGlyphManager::StitchMesh( MeshData& first,
@@ -92,20 +127,31 @@ void AtlasGlyphManager::StitchMesh( MeshData& first,
   mAtlasManager.StitchMesh( first, second );
 }
 
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
                                 uint32_t index,
                                 Dali::Toolkit::AtlasManager::AtlasSlot& slot )
 {
-  for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
   {
-    if ( fontId == mGlyphRecords[ i ].mFontId && index == mGlyphRecords[ i ].mIndex )
+    if ( fontGlyphRecordIt->mFontId == fontId )
     {
-      slot.mImageId = mGlyphRecords[ i ].mImageId;
-      slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
-      return;
+      for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+            glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+            ++glyphRecordIt )
+      {
+        if ( glyphRecordIt->mIndex == index )
+        {
+          slot.mImageId = glyphRecordIt->mImageId;
+          slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
+          return true;
+        }
+      }
     }
   }
   slot.mImageId = 0;
+  return false;
 }
 
 Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
@@ -124,21 +170,6 @@ void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32
   mAtlasManager.SetNewAtlasSize( size );
 }
 
-void AtlasGlyphManager::Remove( uint32_t imageId )
-{
-  if ( mAtlasManager.Remove( imageId ) )
-  {
-    for ( uint32_t i = 0; i < mGlyphRecords.Size(); ++i )
-    {
-      if ( mGlyphRecords[ i ].mImageId == imageId )
-      {
-        mGlyphRecords.Remove( mGlyphRecords.Begin() + i );
-        return;
-      }
-    }
-  }
-}
-
 Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
 {
   return mAtlasManager.GetPixelFormat( atlasId );
@@ -146,11 +177,38 @@ Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
 
 const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
 {
-  mMetrics.mGlyphCount = mGlyphRecords.Size();
+  mMetrics.mGlyphCount = mFontGlyphRecords.size();
   mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
   return mMetrics;
 }
 
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+{
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
+  {
+    if ( fontGlyphRecordIt->mFontId == fontId )
+    {
+      for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+            glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+            ++glyphRecordIt )
+      {
+        if ( glyphRecordIt->mImageId == imageId )
+        {
+          glyphRecordIt->mCount += delta;
+          if ( !glyphRecordIt->mCount )
+          {
+            mAtlasManager.Remove( glyphRecordIt->mImageId );
+            fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+          }
+          return;
+        }
+      }
+    }
+  }
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index cbbe732..5008106 100644 (file)
@@ -49,11 +49,17 @@ class AtlasGlyphManager : public Dali::BaseObject
 {
 public:
 
-  struct GlyphRecord
+  struct GlyphRecordEntry
   {
-    Text::FontId mFontId;
     Text::GlyphIndex mIndex;
     uint32_t mImageId;
+    int32_t mCount;
+  };
+
+  struct FontGlyphRecord
+  {
+    Text::FontId mFontId;
+    Vector< GlyphRecordEntry > mGlyphRecords;
   };
 
   AtlasGlyphManager();
@@ -68,7 +74,8 @@ public:
   /**
    * @copydoc Toolkit::AtlasGlyphManager::Add
    */
-  void Add( const Text::GlyphInfo& glyph,
+  void Add( Text::FontId fontId,
+            const Text::GlyphInfo& glyph,
             const BufferImage& bitmap,
             Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
@@ -88,7 +95,7 @@ public:
   /**
    * @copydoc Toolkit::AtlasGlyphManager::Cached
    */
-  void Cached( Text::FontId fontId,
+  bool Cached( Text::FontId fontId,
                Text::GlyphIndex index,
                Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
@@ -103,11 +110,6 @@ public:
   void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
 
   /**
-   * @copydoc Toolkit::AtlasGlyphManager::Remove
-   */
-  void Remove( uint32_t imageId );
-
-  /**
    * @copydoc toolkit::AtlasGlyphManager::GetPixelFormat
    */
   Pixel::Format GetPixelFormat( uint32_t atlasId );
@@ -117,10 +119,15 @@ public:
    */
   const Toolkit::AtlasGlyphManager::Metrics& GetMetrics();
 
+  /**
+   * @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount
+   */
+  void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+
 private:
 
   Dali::Toolkit::AtlasManager mAtlasManager;
-  Vector< GlyphRecord > mGlyphRecords;
+  std::vector< FontGlyphRecord > mFontGlyphRecords;
   uint32_t mCount;
   Toolkit::AtlasGlyphManager::Metrics mMetrics;
 };
index 37f7ee1..0438314 100644 (file)
@@ -69,11 +69,12 @@ AtlasGlyphManager::AtlasGlyphManager(Internal::AtlasGlyphManager *impl)
 {
 }
 
-void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+void AtlasGlyphManager::Add( Text::FontId fontId,
+                             const Text::GlyphInfo& glyph,
                              const BufferImage& bitmap,
                              AtlasManager::AtlasSlot& slot )
 {
-  GetImplementation(*this).Add( glyph, bitmap, slot );
+  GetImplementation(*this).Add( fontId, glyph, bitmap, slot );
 }
 
 void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
@@ -91,11 +92,11 @@ void AtlasGlyphManager::StitchMesh( MeshData& first,
   GetImplementation(*this).StitchMesh( first, second );
 }
 
-void AtlasGlyphManager::Cached( Text::FontId fontId,
+bool AtlasGlyphManager::Cached( Text::FontId fontId,
                                 Text::GlyphIndex index,
                                 AtlasManager::AtlasSlot& slot )
 {
-  GetImplementation(*this).Cached( fontId, index, slot );
+  return GetImplementation(*this).Cached( fontId, index, slot );
 }
 
 void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
@@ -108,11 +109,6 @@ Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
   return GetImplementation(*this).GetAtlasSize( atlasId );
 }
 
-void AtlasGlyphManager::Remove( uint32_t imageId )
-{
-  GetImplementation(*this).Remove( imageId );
-}
-
 Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
 {
   return GetImplementation(*this).GetPixelFormat( atlasId );
@@ -123,6 +119,11 @@ const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
   return GetImplementation(*this).GetMetrics();
 }
 
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+{
+  GetImplementation(*this).AdjustReferenceCount( fontId, imageId, delta );
+}
+
 } // namespace Toolkit
 
 } // namespace Dali
index ad2c5ea..fdc4141 100644 (file)
@@ -71,11 +71,13 @@ public:
   /**
    * @brief Ask Atlas Manager to add a glyph
    *
+   * @param[in] fontId fontId glyph comes from
    * @param[in] glyph glyph to add to an atlas
    * @param[in] bitmap bitmap to use for glyph addition
    * @param[out] slot information returned by atlas manager for addition
    */
-  void Add( const Text::GlyphInfo& glyph,
+  void Add( Text::FontId fontId,
+            const Text::GlyphInfo& glyph,
             const BufferImage& bitmap,
             AtlasManager::AtlasSlot& slot );
 
@@ -105,8 +107,10 @@ public:
    * @param[in] fontId The font that this glyph comes from
    * @param[in] index The GlyphIndex of this glyph
    * @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached )
+   *
+   * @return Whether glyph is cached or not ?
    */
-  void Cached( Text::FontId fontId,
+  bool Cached( Text::FontId fontId,
                Text::GlyphIndex index,
                AtlasManager::AtlasSlot& slot );
 
@@ -130,13 +134,6 @@ public:
   void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
 
   /**
-   * @brief Unreference an image from the atlas and remove from cache if no longer needed
-   *
-   * @param[in] imageId ID of the image
-   */
-  void Remove( uint32_t imageId );
-
-  /**
    * @brief Get the Pixel Format used by an atlas
    *
    * @param[in] atlasId Id of atlas to check
@@ -152,6 +149,15 @@ public:
    */
   const Metrics& GetMetrics();
 
+  /**
+   * @brief Adjust the reference count for an imageId and remove cache entry if it becomes free
+   *
+   * @param[in] fontId the font this image came from
+   * @param[in] imageId The imageId
+   * @param[in] delta adjustment to make to reference count
+   */
+  void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+
 private:
 
   explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl);
index 58f7fc1..5eca29d 100644 (file)
@@ -80,17 +80,24 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     uint32_t mMeshRecordIndex;
   };
 
-  struct AtlasRecord
+  struct MaxBlockSize
   {
-    uint32_t mImageId;
+    FontId mFontId;
+    uint32_t mNeededBlockWidth;
+    uint32_t mNeededBlockHeight;
+  };
+
+  struct CheckEntry
+  {
+    FontId mFontId;
     Text::GlyphIndex mIndex;
   };
 
-  struct MaxBlockSize
+  struct TextCacheEntry
   {
     FontId mFontId;
-    uint32_t mNeededBlockWidth;
-    uint32_t mNeededBlockHeight;
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
   };
 
   Impl()
@@ -118,6 +125,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
     Vector< Extent > extents;
+    TextCacheEntry textCacheEntry;
 
     float currentUnderlinePosition = ZERO;
     float currentUnderlineThickness = underlineHeight;
@@ -130,10 +138,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       style = STYLE_DROP_SHADOW;
     }
 
-    if ( mImageIds.Size() )
+    if ( mTextCache.Size() )
     {
-      // Unreference any currently used glyphs
-      RemoveText();
+      // Update the glyph cache with any changes to current text
+      RemoveText( glyphs );
     }
 
     CalculateBlocksSize( glyphs );
@@ -183,17 +191,9 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
         const Vector2& position = positions[ i ];
         MeshData newMeshData;
-        mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
 
-        if ( slot.mImageId )
-        {
-          // This glyph already exists so generate mesh data plugging in our supplied position
-          mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
-          mImageIds.PushBack( slot.mImageId );
-        }
-        else
+        if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
         {
-
           // Select correct size for new atlas if needed....?
           if ( lastFontId != glyph.fontId )
           {
@@ -236,16 +236,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker
             }
 
             // Locate a new slot for our glyph
-            mGlyphManager.Add( glyph, bitmap, slot );
-
-            // Generate mesh data for this quad, plugging in our supplied position
-            if ( slot.mImageId )
-            {
-              mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
-              mImageIds.PushBack( slot.mImageId );
-            }
+            mGlyphManager.Add( glyph.fontId, glyph, bitmap, slot );
           }
         }
+
+        // Generate mesh data for this quad, plugging in our supplied position
+        mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
+        textCacheEntry.mFontId = glyph.fontId;
+        textCacheEntry.mImageId = slot.mImageId;
+        textCacheEntry.mIndex = glyph.index;
+        mTextCache.PushBack( textCacheEntry );
+
         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
         StitchTextMesh( meshContainer,
                         newMeshData,
@@ -308,7 +309,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           mActor = actor;
         }
       }
-      mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
     }
 #if defined(DEBUG_ENABLED)
     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
@@ -434,19 +434,56 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  // Unreference any glyphs that were used with this actor
-  void OffStageDisconnect( Dali::Actor actor )
+  void RemoveText( const Vector<GlyphInfo>& glyphs )
   {
-    RemoveText();
-  }
+    Vector< CheckEntry > checked;
+    CheckEntry checkEntry;
 
-  void RemoveText()
-  {
-    for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
+    for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
     {
-      mGlyphManager.Remove( mImageIds[ i ] );
+      uint32_t index = tCit->mIndex;
+      uint32_t fontId = tCit->mFontId;
+
+      // Check that this character has not already been checked...
+      bool wasChecked = false;
+      for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
+      {
+        if ( fontId == cEit->mFontId && index == cEit->mIndex )
+        {
+          wasChecked = true;
+        }
+      }
+
+      if ( !wasChecked )
+      {
+
+        int32_t newCount = 0;
+        int32_t oldCount = 0;
+
+        // How many times does this character occur in the old text ?
+        for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
+        {
+          if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
+          {
+            oldCount++;
+          }
+        }
+
+        // And how many times in the new ?
+        for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
+        {
+          if ( fontId == cGit->fontId && index == cGit->index )
+          {
+            newCount++;
+          }
+        }
+        mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
+        checkEntry.mIndex = index;
+        checkEntry.mFontId = fontId;
+        checked.PushBack( checkEntry );
+      }
     }
-    mImageIds.Resize( 0 );
+    mTextCache.Resize( 0 );
   }
 
   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
@@ -678,13 +715,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   RenderableActor mActor;                             ///< The actor parent which renders the text
   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
-  Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
   ShaderEffect mBasicShader;                          ///> Shader used to render L8 glyphs
   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
   std::vector< MeshData::FaceIndex > mFace;           ///> Face indices for a quad
+  Vector< TextCacheEntry > mTextCache;
 };
 
 Text::RendererPtr AtlasRenderer::New()
@@ -736,5 +773,7 @@ AtlasRenderer::AtlasRenderer()
 
 AtlasRenderer::~AtlasRenderer()
 {
+  Vector< GlyphInfo > emptyGlyphs;
+  mImpl->RemoveText( emptyGlyphs );
   delete mImpl;
 }
index d7ed8f4..4d74def 100644 (file)
@@ -21,6 +21,8 @@
 namespace Dali
 {
 
+class Actor;
+
 namespace Toolkit
 {
 
@@ -45,11 +47,23 @@ public:
   virtual ~ControlInterface();
 
   /**
+   * @brief Add a decoration.
+   *
+   * @param[in] decoration The actor displaying a decoration.
+   */
+  virtual void AddDecoration( Actor& actor ) = 0;
+
+  /**
    * @brief Called to request a text relayout.
    */
   virtual void RequestTextRelayout() = 0;
 
   /**
+   * @brief Called to signal that text has been inserted or deleted.
+   */
+  virtual void TextChanged() = 0;
+
+  /**
    * @brief Called when the number of characters to be inserted exceeds the maximum limit
    */
   virtual void MaxLengthReached() = 0;
index 3020e67..ab2764c 100644 (file)
@@ -231,6 +231,12 @@ struct Controller::Impl
    */
   void QueueModifyEvent( ModifyEvent::Type type )
   {
+    if( ModifyEvent::TEXT_REPLACED == type)
+    {
+      // Cancel previously queued inserts etc.
+      mModifyEvents.clear();
+    }
+
     ModifyEvent event;
     event.type = type;
     mModifyEvents.push_back( event );
index e07e29c..36b566b 100644 (file)
@@ -73,12 +73,11 @@ void Controller::EnableTextInput( DecoratorPtr decorator )
 
 void Controller::SetText( const std::string& text )
 {
-  // Cancel previously queued inserts etc.
-  mImpl->mModifyEvents.clear();
-
   // Remove the previously set text
   ResetText();
 
+  CharacterIndex lastCursorIndex = 0u;
+
   if( !text.empty() )
   {
     //  Convert text into UTF-32
@@ -96,11 +95,8 @@ void Controller::SetText( const std::string& text )
     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
 
-    // Reset the cursor position
-    if( mImpl->mEventData )
-    {
-      mImpl->mEventData->mPrimaryCursorPosition = characterCount;
-    }
+    // To reset the cursor position
+    lastCursorIndex = characterCount;
 
     // Update the rest of the model during size negotiation
     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
@@ -116,6 +112,12 @@ void Controller::SetText( const std::string& text )
     ShowPlaceholderText();
   }
 
+  // Resets the cursor position.
+  ResetCursorPosition( lastCursorIndex );
+
+  // Scrolls the text to make the cursor visible.
+  ResetScrollPosition();
+
   mImpl->RequestRelayout();
 
   if( mImpl->mEventData )
@@ -126,6 +128,9 @@ void Controller::SetText( const std::string& text )
 
   // Reset keyboard as text changed
   mImpl->ResetImfManager();
+
+  // Do this last since it provides callbacks into application code
+  mImpl->mControlInterface.TextChanged();
 }
 
 void Controller::GetText( std::string& text ) const
@@ -672,12 +677,6 @@ void Controller::ResetText()
   mImpl->mLogicalModel->mText.Clear();
   ClearModelData();
 
-  // Reset the cursor position
-  if( mImpl->mEventData )
-  {
-    mImpl->mEventData->mPrimaryCursorPosition = 0;
-  }
-
   // We have cleared everything including the placeholder-text
   mImpl->PlaceholderCleared();
 
@@ -688,6 +687,32 @@ void Controller::ResetText()
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
 
+void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
+{
+  // Reset the cursor position
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
+
+    // Update the cursor if it's in editing mode.
+    if( ( EventData::EDITING == mImpl->mEventData->mState ) ||
+        ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) )
+    {
+      mImpl->mEventData->mUpdateCursorPosition = true;
+    }
+  }
+}
+
+void Controller::ResetScrollPosition()
+{
+  if( NULL != mImpl->mEventData )
+  {
+    // Reset the scroll position.
+    mImpl->mEventData->mScrollPosition = Vector2::ZERO;
+    mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+  }
+}
+
 void Controller::TextReplacedEvent()
 {
   // Reset buffers.
@@ -1089,6 +1114,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
 {
   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
 
+  bool textChanged( false );
+
   if( mImpl->mEventData &&
       keyEvent.state == KeyEvent::Down )
   {
@@ -1131,6 +1158,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
         {
           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
         }
+
+        textChanged = true;
       }
     }
     else
@@ -1141,6 +1170,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->ClearPreEditFlag();
 
       InsertText( keyString, COMMIT );
+
+      textChanged = true;
     }
 
     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
@@ -1148,6 +1179,12 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
     mImpl->RequestRelayout();
   }
 
+  if( textChanged )
+  {
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.TextChanged();
+  }
+
   return false;
 }
 
@@ -1261,9 +1298,10 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
 
-    mImpl->mControlInterface.MaxLengthReached();
-
     mImpl->ResetImfManager();
+
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.MaxLengthReached();
   }
 }
 
@@ -1329,9 +1367,19 @@ void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
   }
 }
 
-void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
+void Controller::GetTargetSize( Vector2& targetSize )
+{
+  targetSize = mImpl->mControlSize;
+}
+
+void Controller::AddDecoration( Actor& actor )
+{
+  mImpl->mControlInterface.AddDecoration( actor );
+}
+
+void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
 {
-  DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
 
   if( mImpl->mEventData )
   {
@@ -1432,6 +1480,9 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
   {
     mImpl->mOperationsPending = ALL_OPERATIONS;
     mImpl->RequestRelayout();
+
+    // Do this last since it provides callbacks into application code
+    mImpl->mControlInterface.TextChanged();
   }
 
   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
@@ -1453,9 +1504,6 @@ void Controller::ShowPlaceholderText()
 
     mImpl->mEventData->mIsShowingPlaceholderText = true;
 
-    // Cancel previously queued inserts etc.
-    mImpl->mModifyEvents.clear();
-
     // Disable handles when showing place-holder text
     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
index 8a780a9..8428699 100644 (file)
@@ -67,9 +67,9 @@ enum PlaceholderType
  * It provides a view of the text that can be used by rendering back-ends.
  *
  * For selectable/editable UI controls, the controller handles input events from the UI control
- * and decorations (grab handles etc) via an observer interface.
+ * and decorations (grab handles etc) via an interface.
  */
-class Controller : public RefObject, public Decorator::Observer
+class Controller : public RefObject, public Decorator::ControllerInterface
 {
 public:
 
@@ -379,6 +379,18 @@ public:
   void ResetText();
 
   /**
+   * @brief Used to reset the cursor position after setting a new text.
+   *
+   * @param[in] cursorIndex Where to place the cursor.
+   */
+  void ResetCursorPosition( CharacterIndex cursorIndex );
+
+  /**
+   * @brief Used to reset the scroll position after setting a new text.
+   */
+  void ResetScrollPosition();
+
+  /**
    * @brief Used to process an event queued from SetText()
    */
   void TextReplacedEvent();
@@ -504,11 +516,6 @@ public:
   void PanEvent( Gesture::State state, const Vector2& displacement );
 
   /**
-   * @copydoc Dali::Toolkit::Text::Decorator::Observer::HandleEvent()
-   */
-  virtual void HandleEvent( HandleType handle, HandleState state, float x, float y );
-
-  /**
    * @brief Event received from IMF manager
    *
    * @param[in] imfManager The IMF manager.
@@ -517,6 +524,21 @@ public:
    */
   ImfManager::ImfCallbackData OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent );
 
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
+   */
+  virtual void GetTargetSize( Vector2& targetSize );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::DecorationEvent()
+   */
+  virtual void DecorationEvent( HandleType handle, HandleState state, float x, float y );
+
 protected:
 
   /**
index 976635a..47a2028 100644 (file)
@@ -116,55 +116,61 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
         {
           const GlyphInfo& glyphToRemove = *( glyphs + index );
 
-          // Need to reshape the glyph as the font may be different in size.
-          const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphToRemove.fontId ) );
-
-          if( !firstPenSet )
+          if( 0u != glyphToRemove.fontId )
           {
-            const Vector2& position = *( glyphPositions + index );
+            // i.e. The font id of the glyph shaped from the '\n' character is zero.
 
-            // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
-            penY = position.y + glyphToRemove.yBearing;
+            // Need to reshape the glyph as the font may be different in size.
+            const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphToRemove.fontId ) );
 
-            // Calculates the first penX which will be used if rtl text is elided.
-            firstPenX = position.x - glyphToRemove.xBearing;
-            if( firstPenX < -ellipsisGlyph.xBearing )
+            if( !firstPenSet )
             {
-              // Avoids to exceed the bounding box when rtl text is elided.
-              firstPenX = -ellipsisGlyph.xBearing;
-            }
+              const Vector2& position = *( glyphPositions + index );
 
-            removedGlypsWidth = -ellipsisGlyph.xBearing;
+              // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+              penY = position.y + glyphToRemove.yBearing;
 
-            firstPenSet = true;
-          }
+              // Calculates the first penX which will be used if rtl text is elided.
+              firstPenX = position.x - glyphToRemove.xBearing;
+              if( firstPenX < -ellipsisGlyph.xBearing )
+              {
+                // Avoids to exceed the bounding box when rtl text is elided.
+                firstPenX = -ellipsisGlyph.xBearing;
+              }
 
-          removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+              removedGlypsWidth = -ellipsisGlyph.xBearing;
 
-          // Calculate the width of the ellipsis glyph and check if it fits.
-          const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
-          if( ellipsisGlyphWidth < removedGlypsWidth )
-          {
-            GlyphInfo& glyphInfo = *( glyphs + index );
-            Vector2& position = *( glyphPositions + index );
-            position.x -= glyphInfo.xBearing;
-
-            // Replace the glyph by the ellipsis glyph.
-            glyphInfo = ellipsisGlyph;
+              firstPenSet = true;
+            }
 
-            // Change the 'x' and 'y' position of the ellipsis glyph.
+            removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
 
-            if( position.x > firstPenX )
+            // Calculate the width of the ellipsis glyph and check if it fits.
+            const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+            if( ellipsisGlyphWidth < removedGlypsWidth )
             {
-              position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
-            }
+              GlyphInfo& glyphInfo = *( glyphs + index );
+              Vector2& position = *( glyphPositions + index );
+              position.x -= glyphInfo.xBearing;
 
-            position.x += ellipsisGlyph.xBearing;
-            position.y = penY - ellipsisGlyph.yBearing;
+              // Replace the glyph by the ellipsis glyph.
+              glyphInfo = ellipsisGlyph;
 
-            inserted = true;
+              // Change the 'x' and 'y' position of the ellipsis glyph.
+
+              if( position.x > firstPenX )
+              {
+                position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+              }
+
+              position.x += ellipsisGlyph.xBearing;
+              position.y = penY - ellipsisGlyph.yBearing;
+
+              inserted = true;
+            }
           }
-          else
+
+          if( !inserted )
           {
             if( index > 0u )
             {
index 1cb02bf..0d7a2f0 100644 (file)
@@ -797,6 +797,9 @@ Control::Control( ControlBehaviour behaviourFlags )
 
 void Control::Initialize()
 {
+  // Call deriving classes so initialised before styling is applied to them.
+  OnInitialize();
+
   if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
   {
     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
@@ -804,7 +807,7 @@ void Control::Initialize()
     // Register for style changes
     styleManager.StyleChangeSignal().Connect( this, &Control::OnStyleChange );
 
-    // SetTheme
+    // Apply the current style
     GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
   }
 
@@ -812,9 +815,6 @@ void Control::Initialize()
   {
     SetKeyboardNavigationSupport( true );
   }
-
-  // Calling deriving classes
-  OnInitialize();
 }
 
 void Control::OnInitialize()
index 5340137..3a833f3 100644 (file)
@@ -59,6 +59,11 @@ TextField TextField::DownCast( BaseHandle handle )
   return Control::DownCast<TextField, Internal::TextField>(handle);
 }
 
+TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).TextChangedSignal();
+}
+
 TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
 {
   return Dali::Toolkit::GetImpl( *this ).MaxLengthReachedSignal();
index 1f6df9b..4f3da41 100644 (file)
@@ -38,6 +38,7 @@ class TextField;
  *  * Signals
  * | %Signal Name           | Method                                              |
  * |------------------------|-----------------------------------------------------|
+ * | text-changed           | @ref TextChangedSignal()                            |
  * | max-length-reached     | @ref MaxLengthReachedSignal()                       |
  *
  */
@@ -109,6 +110,7 @@ public:
   // Type Defs
 
   /// @brief Max Characters Exceed signal type;
+  typedef Signal<void ( TextField ) > TextChangedSignalType;
   typedef Signal<void ( TextField ) > MaxLengthReachedSignalType;
 
   /**
@@ -158,6 +160,17 @@ public:
   // Signals
 
   /**
+   * @brief This signal is emitted when the text changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TextField textField );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  TextChangedSignalType& TextChangedSignal();
+
+  /**
    * @brief This signal is emitted when inserted text exceeds the maximum character limit.
    *
    * A callback of the following type may be connected:
index 59e5a69..c7121dc 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 43;
+const unsigned int TOOLKIT_MICRO_VERSION = 44;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
diff --git a/docs/content/images/item-view/depth.png b/docs/content/images/item-view/depth.png
new file mode 100644 (file)
index 0000000..86c879d
Binary files /dev/null and b/docs/content/images/item-view/depth.png differ
diff --git a/docs/content/images/item-view/grid.png b/docs/content/images/item-view/grid.png
new file mode 100644 (file)
index 0000000..398da01
Binary files /dev/null and b/docs/content/images/item-view/grid.png differ
diff --git a/docs/content/images/item-view/spiral.png b/docs/content/images/item-view/spiral.png
new file mode 100644 (file)
index 0000000..1825a11
Binary files /dev/null and b/docs/content/images/item-view/spiral.png differ
index 27937d2..c34c256 100644 (file)
@@ -56,7 +56,7 @@
  + Buttons
  + TableView
  + [Scroll View](@ref scroll-view)
- + ItemView
+ + [ItemView](@ref item-view)
 
 ### RenderTasks
 
diff --git a/docs/content/programming-guide/item-view.h b/docs/content/programming-guide/item-view.h
deleted file mode 100644 (file)
index 43cd656..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*! \page item-view Item View
- * Your text here
- *
- * References to Dali::Toolkit::ItemView will work...
- *
- */
-
diff --git a/docs/content/shared-javascript-and-cpp-documentation/item-view.md b/docs/content/shared-javascript-and-cpp-documentation/item-view.md
new file mode 100644 (file)
index 0000000..1313253
--- /dev/null
@@ -0,0 +1,73 @@
+<!--
+/**-->
+
+# Item View {#item-view}
+
+An Item view is a scrollable container that contains several items.
+It can have several layouts.
+There are a few built-in layouts that the application writer can use:
+
+|GRID                    |SPIRAL                    |DEPTH                    |
+|:----------------------:|:------------------------:|:-----------------------:|
+|![ ](item-view/grid.png)|![ ](item-view/spiral.png)|![ ](item-view/depth.png)|
+
+The application writer can also create their own custom layout by inheriting from Dali::Toolkit::ItemLayout.
+
+## Item Factory
+
+To create an item-view, the application writer has to provide an item-factory.
+An ItemFactory provides methods to create items and how many items there are among other things.
+
+~~~{.cpp}
+class MyFactory : public Dali::Toolkit::ItemFactory
+{
+public:
+  virtual unsigned int GetNumberOfItems()
+  {
+    // Should return the number of items
+    return MY_ITEM_COUNT;
+  }
+
+  virtual Actor NewItem( unsigned int itemId )
+  {
+    // We should create the actor here that represents our item based on the itemId given.
+
+    // Here we'll create an ImageActor which uses the the itemId to parse the image in a particular directory.
+    std::ostringstream imageName;
+    imageName << "my-image-folder/" << itemId << ".png"; // If item was 10, then this would result in my-image-folder/10.png
+    Dali::ResourceImage image = Dali::ResourceImage::New( imageName.str() );
+
+    // Create an Image Actor from the image and return
+    return Dali::ImageActor::New( image );
+  }
+};
+~~~
+These overridden methods in our factory will be called by the Item View.
+
+## Creating an ItemView
+
+~~~{.cpp}
+MyFactory factory; // Should store this as a member variable
+Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::New( factory ); // Pass in our factory
+itemView.SetParentOrigin( ParentOrigin::CENTER );
+itemView.SetAnchorPoint( AnchorPoint::CENTER );
+
+// Now create a layout
+Dali::Toolkit::ItemLayoutPtr spiralLayout = Dali::Toolkit::DefaultItemLayout::New( Dali::Toolkit::DefaultItemLayout::SPIRAL );
+
+// ... and add the layout to the item view
+itemView.AddLayout( spiralLayout );
+
+// More layouts can be created and added to the item-view
+
+// Activate the layout
+itemView.ActivateLayout(
+  0,                                   // The layout ID matches the order in which layouts are added
+  Dali::Stage::GetCurrent().GetSize(), // Use the stage's size as our item-view size
+  0 );                                 // We want the item-view to appear straight away
+
+// And add to the stage
+Dali::Stage::GetCurrent().Add( itemView );
+~~~
+
+*/
\ No newline at end of file
index de3867f..13bff90 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.0.43
+Version:    1.0.44
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0