Resource ready signal for Controls (for ImageLoading) 64/123864/10
authorNick Holland <nick.holland@partner.samsung.com>
Fri, 7 Apr 2017 08:52:32 +0000 (09:52 +0100)
committerNick Holland <nick.holland@partner.samsung.com>
Wed, 19 Apr 2017 08:18:57 +0000 (01:18 -0700)
Change does the following:

Add Observer to Visual::Base for resource ready
Add signal to Control (Base)
Implement Observer in Control::Impl when Visual is Registered

Call the Observer from Image/Svg/etc Visual when they add the Renderer to Actor (this is usually when the visual is placed or stage or when async load completes).

Currently the signal will only fire when the control is on stage and all resources are loaded (async and sync).

Public API change note: This patch changes the declaration of Control::Impl from private to public, however this does not effect any exported symbols, so should keep binary compatibility. Also the class is not accessible externally as it's definition is not exposed.

Change-Id: I6e906e4f29de0af3b0ed465a643c078fc902b1e5

25 files changed:
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/devel-api/controls/control-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/file.list
dali-toolkit/internal/controls/control/control-data-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-data-impl.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/border/border-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/mesh/mesh-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/primitive/primitive-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h
dali-toolkit/internal/visuals/visual-resource-observer.h [new file with mode: 0644]
dali-toolkit/internal/visuals/wireframe/wireframe-visual.cpp
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/control-impl.h

index 596d09a..d1beb09 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali/public-api/rendering/renderer.h>
 
 #include <test-native-image.h>
@@ -840,6 +841,46 @@ int UtcDaliImageViewSetImageOffstageP(void)
   END_TEST;
 }
 
+bool gResourceReadySignalFired = false;
+
+void ResourceReadySignal( Control control )
+{
+  gResourceReadySignalFired = true;
+}
+
+int UtcDaliImageViewCheckResourceReady(void)
+{
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+
+  int width = 100;
+  int height = 200;
+  Image image = CreateBufferImage( width, height, Vector4(1.f, 1.f, 1.f, 1.f) );
+
+  // Check ImageView with background and main image, to ensure both visuals are marked as loaded
+  ImageView imageView = ImageView::New( TEST_GIF_FILE_NAME );
+
+  imageView.SetBackgroundImage( image );
+
+  DALI_TEST_EQUALS( Toolkit::DevelControl::IsResourceReady( imageView ), false, TEST_LOCATION );
+
+  Toolkit::DevelControl::ResourceReadySignal( imageView ).Connect( &ResourceReadySignal);
+
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render(16);
+
+
+  DALI_TEST_EQUALS( Toolkit::DevelControl::IsResourceReady( imageView ), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliImageViewSetImageOffstageN(void)
 {
   ToolkitTestApplication application;
diff --git a/dali-toolkit/devel-api/controls/control-devel.cpp b/dali-toolkit/devel-api/controls/control-devel.cpp
new file mode 100644 (file)
index 0000000..648602f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 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 "control-devel.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelControl
+{
+
+ResourceReadySignalType&  ResourceReadySignal( Control& control )
+{
+
+  Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
+  Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl );
+
+  return controlImpl.mResourceReadySignal;
+}
+
+bool IsResourceReady( const Control& control )
+{
+  const Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
+  const Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl );
+
+  return controlImpl.IsResourceReady();
+}
+
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
index b6ddd7e..63f5cf9 100644 (file)
@@ -108,6 +108,29 @@ enum
 
 } // namespace Property
 
+/// @brief ResourceReady signal type;
+typedef Signal<void ( Control ) > ResourceReadySignalType;
+
+/**
+ * @brief This signal is emitted after all resources required
+ * by a control are loaded and ready.
+ * Most resources are only loaded when the control is placed on stage.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Control control );
+ * @endcode
+ */
+ResourceReadySignalType& ResourceReadySignal( Control& control );
+
+/**
+ * @brief Query if all resources required by a control are loaded and ready.
+ * Most resources are only loaded when the control is placed on stage.
+ * @return true if the resources are loaded and ready, false otherwise
+ *
+ */
+bool IsResourceReady( const Control& control );
+
 } // namespace DevelControl
 
 } // namespace Toolkit
index d7c45f5..a434aef 100644 (file)
@@ -4,6 +4,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/builder/builder.cpp \
   $(devel_api_src_dir)/builder/json-parser.cpp \
   $(devel_api_src_dir)/builder/tree-node.cpp \
+  $(devel_api_src_dir)/controls/control-devel.cpp \
   $(devel_api_src_dir)/controls/control-wrapper.cpp \
   $(devel_api_src_dir)/controls/control-wrapper-impl.cpp \
   $(devel_api_src_dir)/controls/bloom-view/bloom-view.cpp \
diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp
new file mode 100644 (file)
index 0000000..38c9a57
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2017 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 "control-data-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+extern const Dali::Scripting::StringEnum ControlStateTable[];
+extern const unsigned int ControlStateTableCount;
+
+
+// Not static or anonymous - shared with other translation units
+const Scripting::StringEnum ControlStateTable[] = {
+  { "NORMAL",   Toolkit::DevelControl::NORMAL   },
+  { "FOCUSED",  Toolkit::DevelControl::FOCUSED  },
+  { "DISABLED", Toolkit::DevelControl::DISABLED },
+};
+const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] );
+
+
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+
+template<typename T>
+void Remove( Dictionary<T>& keyValues, const std::string& name )
+{
+  keyValues.Remove(name);
+}
+
+void Remove( DictionaryKeys& keys, const std::string& name )
+{
+  DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name );
+  if( iter != keys.end())
+  {
+    keys.erase(iter);
+  }
+}
+
+Toolkit::DevelVisual::Type GetVisualTypeFromMap( const Property::Map& map )
+{
+  Property::Value* typeValue = map.Find( Toolkit::DevelVisual::Property::TYPE, VISUAL_TYPE  );
+  Toolkit::DevelVisual::Type type = Toolkit::DevelVisual::IMAGE;
+  if( typeValue )
+  {
+    Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type );
+  }
+  return type;
+}
+
+void FindChangableVisuals( Dictionary<Property::Map>& stateVisualsToAdd,
+                           Dictionary<Property::Map>& stateVisualsToChange,
+                           DictionaryKeys& stateVisualsToRemove)
+{
+  DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
+
+  for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
+       iter != copyOfStateVisualsToRemove.end(); ++iter )
+  {
+    const std::string& visualName = (*iter);
+    Property::Map* toMap = stateVisualsToAdd.Find( visualName );
+    if( toMap )
+    {
+      stateVisualsToChange.Add( visualName, *toMap );
+      stateVisualsToAdd.Remove( visualName );
+      Remove( stateVisualsToRemove, visualName );
+    }
+  }
+}
+
+/**
+ * Performs actions as requested using the action name.
+ * @param[in] object The object on which to perform the action.
+ * @param[in] actionName The action to perform.
+ * @param[in] attributes The attributes with which to perfrom this action.
+ * @return true if action has been accepted by this control
+ */
+const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
+static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
+  {
+    Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+    if( control )
+    {
+      // if cast succeeds there is an implementation so no need to check
+      ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
+    }
+  }
+
+  return ret;
+}
+
+/**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+const char* SIGNAL_KEY_EVENT = "keyEvent";
+const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
+const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
+const char* SIGNAL_TAPPED = "tapped";
+const char* SIGNAL_PANNED = "panned";
+const char* SIGNAL_PINCHED = "pinched";
+const char* SIGNAL_LONG_PRESSED = "longPressed";
+static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( false );
+  Toolkit::Control control = Toolkit::Control::DownCast( handle );
+  if ( control )
+  {
+    Internal::Control& controlImpl( Internal::GetImplementation( control ) );
+    connected = true;
+
+    if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
+    {
+      controlImpl.KeyEventSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
+    {
+      controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
+    {
+      controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Tap );
+      controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Pan );
+      controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Pinch );
+      controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::LongPress );
+      controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+  }
+  return connected;
+}
+
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Internal::Control::New();
+}
+// Setup signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
+
+// Note: Properties are registered separately below.
+
+SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
+SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
+SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
+SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
+SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
+SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
+SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
+
+TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
+
+DALI_TYPE_REGISTRATION_END()
+
+
+
+} // unnamed namespace
+
+
+// Properties registered without macro to use specific member variables.
+const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName",              Toolkit::Control::Property::STYLE_NAME,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgroundColor",        Toolkit::Control::Property::BACKGROUND_COLOR,             Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage",        Toolkit::Control::Property::BACKGROUND_IMAGE,             Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",          Toolkit::Control::Property::KEY_INPUT_FOCUS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",             Toolkit::Control::Property::BACKGROUND,                   Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "tooltip",                Toolkit::DevelControl::Property::TOOLTIP,                 Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "state",                  Toolkit::DevelControl::Property::STATE,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "subState",               Toolkit::DevelControl::Property::SUB_STATE,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "leftFocusableActorId",   Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "upFocusableActorId",    Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,   Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "downFocusableActorId",  Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+
+
+
+Control::Impl::Impl( Control& controlImpl )
+: mControlImpl( controlImpl ),
+  mState( Toolkit::DevelControl::NORMAL ),
+  mSubStateName(""),
+  mLeftFocusableActorId( -1 ),
+  mRightFocusableActorId( -1 ),
+  mUpFocusableActorId( -1 ),
+  mDownFocusableActorId( -1 ),
+  mStyleName(""),
+  mBackgroundColor(Color::TRANSPARENT),
+  mStartingPinchScale( NULL ),
+  mKeyEventSignal(),
+  mPinchGestureDetector(),
+  mPanGestureDetector(),
+  mTapGestureDetector(),
+  mLongPressGestureDetector(),
+  mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mIsKeyboardNavigationSupported( false ),
+  mIsKeyboardFocusGroup( false )
+{
+
+}
+
+Control::Impl::~Impl()
+{
+  // All gesture detectors will be destroyed so no need to disconnect.
+  delete mStartingPinchScale;
+}
+
+Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
+{
+  return *internalControl.mImpl;
+}
+
+const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
+{
+  return *internalControl.mImpl;
+}
+
+
+
+
+Toolkit::Visual::Base Control::Impl::GetVisualByName(
+   RegisteredVisualContainer& visuals,
+  const std::string& visualName )
+{
+  Toolkit::Visual::Base visualHandle;
+
+  RegisteredVisualContainer::Iterator iter;
+  for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
+  {
+    Toolkit::Visual::Base visual = (*iter)->visual;
+    if( visual && visual.GetName() == visualName )
+    {
+      visualHandle = visual;
+      break;
+    }
+  }
+  return visualHandle;
+}
+
+// Gesture Detection Methods
+void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
+{
+  mControlImpl.OnPinch(pinch);
+}
+
+void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
+{
+  mControlImpl.OnPan(pan);
+}
+
+void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
+{
+  mControlImpl.OnTap(tap);
+}
+
+void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
+{
+  mControlImpl.OnLongPress(longPress);
+}
+
+// Called by a Visual when it's resource is ready
+void Control::Impl::ResourceReady( Visual::Base& object)
+{
+
+  // go through and check if all the visuals are ready, if they are emit a signal
+  for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
+        visualIter != mVisuals.End(); ++visualIter )
+  {
+    const Toolkit::Visual::Base visual = (*visualIter)->visual;
+    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+    // one of the visuals is not ready
+    if( !visualImpl.IsResourceReady() )
+    {
+      return;
+    }
+  }
+
+  // all the visuals are ready
+  Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
+  mResourceReadySignal.Emit( handle );
+
+}
+
+bool Control::Impl::IsResourceReady() const
+{
+  // go through and check all the visuals are ready
+  for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
+         visualIter != mVisuals.End(); ++visualIter )
+   {
+     const Toolkit::Visual::Base visual = (*visualIter)->visual;
+     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+     // one of the visuals is not ready
+     if( !visualImpl.IsResourceReady()  )
+     {
+       return false;
+     }
+   }
+  return true;
+}
+void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+  // Stop observing the visual
+  visualImpl.RemoveResourceObserver( *this );
+}
+
+void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+  // start observing the visual for resource ready
+  visualImpl.AddResourceObserver( *this );
+}
+
+// Properties
+
+/**
+ * Called when a property of an object of this type is set.
+ * @param[in] object The object whose property is set.
+ * @param[in] index The property index.
+ * @param[in] value The new property value.
+ */
+void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+
+  if ( control )
+  {
+    Control& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case Toolkit::Control::Property::STYLE_NAME:
+      {
+        controlImpl.SetStyleName( value.Get< std::string >() );
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::STATE:
+      {
+        bool withTransitions=true;
+        const Property::Value* valuePtr=&value;
+        Property::Map* map = value.GetMap();
+        if(map)
+        {
+          Property::Value* value2 = map->Find("withTransitions");
+          if( value2 )
+          {
+            withTransitions = value2->Get<bool>();
+          }
+
+          valuePtr = map->Find("state");
+        }
+
+        if( valuePtr )
+        {
+          Toolkit::DevelControl::State state( controlImpl.mImpl->mState );
+          if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) )
+          {
+            controlImpl.mImpl->SetState( state, withTransitions );
+          }
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::SUB_STATE:
+      {
+        std::string subState;
+        if( value.Get( subState ) )
+        {
+          controlImpl.mImpl->SetSubState( subState );
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mLeftFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mRightFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mUpFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mDownFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::Control::Property::BACKGROUND_COLOR:
+      {
+        DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
+        controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND_IMAGE:
+      {
+        DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
+        Image image = Scripting::NewImage( value );
+        if ( image )
+        {
+          controlImpl.SetBackgroundImage( image );
+        }
+        else
+        {
+          // An empty image means the background is no longer required
+          controlImpl.ClearBackground();
+        }
+        break;
+      }
+
+      case Toolkit::Control::Property::KEY_INPUT_FOCUS:
+      {
+        if ( value.Get< bool >() )
+        {
+          controlImpl.SetKeyInputFocus();
+        }
+        else
+        {
+          controlImpl.ClearKeyInputFocus();
+        }
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND:
+      {
+        std::string url;
+        Vector4 color;
+        const Property::Map* map = value.GetMap();
+        if( map && !map->Empty() )
+        {
+          controlImpl.SetBackground( *map );
+        }
+        else if( value.Get( url ) )
+        {
+          // don't know the size to load
+          Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
+          if( visual )
+          {
+            controlImpl.RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
+            visual.SetDepthIndex( DepthIndex::BACKGROUND );
+          }
+        }
+        else if( value.Get( color ) )
+        {
+          controlImpl.SetBackgroundColor(color);
+        }
+        else
+        {
+          // The background is an empty property map, so we should clear the background
+          controlImpl.ClearBackground();
+        }
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::TOOLTIP:
+      {
+        TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
+        if( ! tooltipPtr )
+        {
+          tooltipPtr = Tooltip::New( control );
+        }
+        tooltipPtr->SetProperties( value );
+      }
+    }
+  }
+}
+
+/**
+ * Called to retrieve a property of an object of this type.
+ * @param[in] object The object whose property is to be retrieved.
+ * @param[in] index The property index.
+ * @return The current value of the property.
+ */
+Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+
+  if ( control )
+  {
+    Control& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case Toolkit::Control::Property::STYLE_NAME:
+      {
+        value = controlImpl.GetStyleName();
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::STATE:
+      {
+        value = controlImpl.mImpl->mState;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::SUB_STATE:
+      {
+        value = controlImpl.mImpl->mSubStateName;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mLeftFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mRightFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mUpFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mDownFocusableActorId;
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND_COLOR:
+      {
+        DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
+        value = controlImpl.GetBackgroundColor();
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND_IMAGE:
+      {
+        DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
+        Property::Map map;
+        Toolkit::Visual::Base visual = controlImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+        value = map;
+        break;
+      }
+
+      case Toolkit::Control::Property::KEY_INPUT_FOCUS:
+      {
+        value = controlImpl.HasKeyInputFocus();
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND:
+      {
+        Property::Map map;
+        Toolkit::Visual::Base visual = controlImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+
+        value = map;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::TOOLTIP:
+      {
+        Property::Map map;
+        if( controlImpl.mImpl->mTooltip )
+        {
+          controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
+        }
+        value = map;
+        break;
+      }
+
+    }
+  }
+
+  return value;
+}
+
+
+void  Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
+{
+  for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
+  {
+    if( (*iter)->visual )
+    {
+      Property::Map instanceMap;
+      Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
+      instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
+    }
+  }
+}
+
+
+void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
+{
+  Actor self( mControlImpl.Self() );
+
+  for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
+        visualIter != visuals.End(); ++visualIter )
+  {
+    Toolkit::Visual::Base visual = (*visualIter)->visual;
+    if( visual && visual.GetName() == visualName )
+    {
+      Toolkit::GetImplementation(visual).SetOffStage( self );
+      (*visualIter)->visual.Reset();
+      visuals.Erase( visualIter );
+      break;
+    }
+  }
+}
+
+void Control::Impl::RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
+{
+  Actor self( mControlImpl.Self() );
+  for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
+  {
+    const std::string visualName = *iter;
+    RemoveVisual( visuals, visualName );
+  }
+}
+
+
+/**
+ * Go through the list of visuals that are common to both states.
+ * If they are different types, or are both image types with different
+ * URLs, then the existing visual needs moving and the new visual creating
+ */
+void Control::Impl::RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
+                             Dictionary<Property::Map>& instancedProperties )
+{
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
+       iter != stateVisualsToChange.End(); ++iter )
+  {
+    const std::string& visualName = (*iter).key;
+    const Property::Map& toMap = (*iter).entry;
+
+    // is it a candidate for re-creation?
+    bool recreate = false;
+
+    Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
+    if( visual )
+    {
+      Property::Map fromMap;
+      visual.CreatePropertyMap( fromMap );
+
+      Toolkit::DevelVisual::Type fromType = GetVisualTypeFromMap( fromMap );
+      Toolkit::DevelVisual::Type toType = GetVisualTypeFromMap( toMap );
+
+      if( fromType != toType )
+      {
+        recreate = true;
+      }
+      else
+      {
+        if( fromType == Toolkit::DevelVisual::IMAGE || fromType == Toolkit::DevelVisual::N_PATCH
+            || fromType == Toolkit::DevelVisual::SVG || fromType == Toolkit::DevelVisual::ANIMATED_IMAGE )
+        {
+          Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+          Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+
+          if( fromUrl && toUrl )
+          {
+            std::string fromUrlString;
+            std::string toUrlString;
+            fromUrl->Get(fromUrlString);
+            toUrl->Get(toUrlString);
+
+            if( fromUrlString != toUrlString )
+            {
+              recreate = true;
+            }
+          }
+        }
+      }
+
+      const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
+      if( recreate || instancedMap )
+      {
+        RemoveVisual( mVisuals, visualName );
+        Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+      }
+      else
+      {
+        // @todo check to see if we can apply toMap without recreating the visual
+        // e.g. by setting only animatable properties
+        // For now, recreate all visuals, but merge in instance data.
+        RemoveVisual( mVisuals, visualName );
+        Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+      }
+    }
+  }
+}
+
+void Control::Impl::ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
+{
+  // Collect all old visual names
+  DictionaryKeys stateVisualsToRemove;
+  if( oldState )
+  {
+    oldState->visuals.GetKeys( stateVisualsToRemove );
+    if( ! subState.empty() )
+    {
+      const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
+      if( oldSubState )
+      {
+        DictionaryKeys subStateVisualsToRemove;
+        (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
+        Merge( stateVisualsToRemove, subStateVisualsToRemove );
+      }
+    }
+  }
+
+  // Collect all new visual properties
+  Dictionary<Property::Map> stateVisualsToAdd;
+  if( newState )
+  {
+    stateVisualsToAdd = newState->visuals;
+    if( ! subState.empty() )
+    {
+      const StylePtr* newSubState = newState->subStates.FindConst(subState);
+      if( newSubState )
+      {
+        stateVisualsToAdd.Merge( (*newSubState)->visuals );
+      }
+    }
+  }
+
+  // If a name is in both add/remove, move it to change list.
+  Dictionary<Property::Map> stateVisualsToChange;
+  FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
+
+  // Copy instanced properties (e.g. text label) of current visuals
+  Dictionary<Property::Map> instancedProperties;
+  CopyInstancedProperties( mVisuals, instancedProperties );
+
+  // For each visual in remove list, remove from mVisuals
+  RemoveVisuals( mVisuals, stateVisualsToRemove );
+
+  // For each visual in add list, create and add to mVisuals
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
+
+  // For each visual in change list, if it requires a new visual,
+  // remove old visual, create and add to mVisuals
+  RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
+}
+
+void Control::Impl::SetState( DevelControl::State newState, bool withTransitions )
+{
+  DevelControl::State oldState = mState;
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
+                (mState == DevelControl::NORMAL ? "NORMAL" :(
+                  mState == DevelControl::FOCUSED ?"FOCUSED" : (
+                    mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
+
+  if( mState != newState )
+  {
+    // If mState was Disabled, and new state is Focused, should probably
+    // store that fact, e.g. in another property that FocusManager can access.
+    mState = newState;
+
+    // Trigger state change and transitions
+    // Apply new style, if stylemanager is available
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+
+      if( stylePtr )
+      {
+        std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
+        std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
+
+        const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
+        const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
+        if( oldStateStyle && newStateStyle )
+        {
+          // Only change if both state styles exist
+          ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
+        }
+      }
+    }
+  }
+}
+
+void Control::Impl::SetSubState( const std::string& subStateName, bool withTransitions )
+{
+  if( mSubStateName != subStateName )
+  {
+    // Get existing sub-state visuals, and unregister them
+    Dali::CustomActor handle( mControlImpl.GetOwner() );
+
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+      if( stylePtr )
+      {
+        // Stringify state
+        std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount );
+
+        const StylePtr* state = stylePtr->subStates.Find( stateName );
+        if( state )
+        {
+          StylePtr stateStyle(*state);
+
+          const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
+          const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
+          if( oldStateStyle && newStateStyle )
+          {
+            std::string empty;
+            ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
+          }
+        }
+      }
+    }
+
+    mSubStateName = subStateName;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/control/control-data-impl.h b/dali-toolkit/internal/controls/control/control-data-impl.h
new file mode 100644 (file)
index 0000000..4adfe65
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef DALI_TOOLKIT_CONTROL_DATA_IMPL_H
+#define DALI_TOOLKIT_CONTROL_DATA_IMPL_H
+
+/*
+ * Copyright (c) 2016 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/object/type-registry.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-resource-observer.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/internal/controls/tooltip/tooltip.h>
+#include <dali-toolkit/internal/builder/style.h>
+#include <dali-toolkit/internal/builder/dictionary.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+  * Struct used to store Visual within the control, index is a unique key for each visual.
+  */
+ struct RegisteredVisual
+ {
+   Property::Index index;
+   Toolkit::Visual::Base visual;
+   bool enabled;
+
+   RegisteredVisual( Property::Index aIndex, Toolkit::Visual::Base &aVisual, bool aEnabled)
+   : index(aIndex), visual(aVisual), enabled(aEnabled)
+   {
+   }
+ };
+
+typedef Dali::OwnerContainer< RegisteredVisual* > RegisteredVisualContainer;
+
+
+/**
+ * Holds the Implementation for the internal control class
+ */
+class Control::Impl : public ConnectionTracker, public Visual::ResourceObserver
+{
+
+public:
+
+  static Control::Impl& Get( Internal::Control& internalControl );
+
+  static const Control::Impl& Get( const Internal::Control& internalControl );
+
+
+  Impl( Control& controlImpl );
+
+  ~Impl();
+
+  void PinchDetected(Actor actor, const PinchGesture& pinch);
+
+  void PanDetected(Actor actor, const PanGesture& pan);
+
+  void TapDetected(Actor actor, const TapGesture& tap);
+
+  void LongPressDetected(Actor actor, const LongPressGesture& longPress);
+
+  void ResourceReady( Visual::Base& object);
+
+  void StopObservingVisual( Toolkit::Visual::Base& visual );
+
+  void StartObservingVisual( Toolkit::Visual::Base& visual);
+
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  void SetState( DevelControl::State newState, bool withTransitions=true );
+
+  void SetSubState( const std::string& subStateName, bool withTransitions=true );
+
+  void ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState );
+
+  void RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName );
+
+  void RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals );
+
+  void  CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties );
+
+  void RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange, Dictionary<Property::Map>& instancedProperties );
+
+  Toolkit::Visual::Base GetVisualByName( RegisteredVisualContainer& visuals, const std::string& visualName );
+
+  bool IsResourceReady() const;
+
+  Control& mControlImpl;
+  DevelControl::State mState;
+  std::string mSubStateName;
+
+  int mLeftFocusableActorId;       ///< Actor ID of Left focusable control.
+  int mRightFocusableActorId;      ///< Actor ID of Right focusable control.
+  int mUpFocusableActorId;         ///< Actor ID of Up focusable control.
+  int mDownFocusableActorId;       ///< Actor ID of Down focusable control.
+
+
+  RegisteredVisualContainer mVisuals;     ///< Stores visuals needed by the control, non trivial type so std::vector used.
+  std::string mStyleName;
+  Vector4 mBackgroundColor;               ///< The color of the background visual
+  Vector3* mStartingPinchScale;           ///< The scale when a pinch gesture starts, TODO: consider removing this
+  Toolkit::Control::KeyEventSignalType mKeyEventSignal;
+  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusGainedSignal;
+  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusLostSignal;
+
+  Toolkit::DevelControl::ResourceReadySignalType mResourceReadySignal;
+
+  // Gesture Detection
+  PinchGestureDetector mPinchGestureDetector;
+  PanGestureDetector mPanGestureDetector;
+  TapGestureDetector mTapGestureDetector;
+  LongPressGestureDetector mLongPressGestureDetector;
+
+  // Tooltip
+  TooltipPtr mTooltip;
+
+  ControlBehaviour mFlags : CONTROL_BEHAVIOUR_FLAG_COUNT;    ///< Flags passed in from constructor.
+  bool mIsKeyboardNavigationSupported :1;  ///< Stores whether keyboard navigation is supported by the control.
+  bool mIsKeyboardFocusGroup :1;           ///< Stores whether the control is a focus group.
+
+  // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
+  static const PropertyRegistration PROPERTY_1;
+  static const PropertyRegistration PROPERTY_2;
+  static const PropertyRegistration PROPERTY_3;
+  static const PropertyRegistration PROPERTY_4;
+  static const PropertyRegistration PROPERTY_5;
+  static const PropertyRegistration PROPERTY_6;
+  static const PropertyRegistration PROPERTY_7;
+  static const PropertyRegistration PROPERTY_8;
+  static const PropertyRegistration PROPERTY_9;
+  static const PropertyRegistration PROPERTY_10;
+  static const PropertyRegistration PROPERTY_11;
+  static const PropertyRegistration PROPERTY_12;
+
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DATA_IMPL_H
index c0dd44b..67b6c9e 100644 (file)
@@ -46,6 +46,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/buttons/push-button-impl.cpp \
    $(toolkit_src_dir)/controls/buttons/radio-button-impl.cpp \
    $(toolkit_src_dir)/controls/buttons/toggle-button-impl.cpp \
+   $(toolkit_src_dir)/controls/control/control-data-impl.cpp \
    $(toolkit_src_dir)/controls/effects-view/effects-view-impl.cpp \
    $(toolkit_src_dir)/controls/flex-container/flex-container-impl.cpp \
    $(toolkit_src_dir)/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp \
index 217994e..0ba7833 100644 (file)
@@ -186,6 +186,9 @@ void AnimatedImageVisual::DoSetOnStage( Actor& actor )
     }
 
     actor.AddRenderer( mImpl->mRenderer );
+
+    // Animated Image loaded and ready to display
+    ResourceReady();
   }
 }
 
index 2329167..0adfa8d 100644 (file)
@@ -215,6 +215,9 @@ void BorderVisual::DoSetOnStage( Actor& actor )
   mBorderSizeIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::BorderVisual::Property::SIZE, SIZE_NAME, mBorderSize );
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Border Visual Generated and ready to display
+  ResourceReady();
 }
 
 void BorderVisual::DoCreatePropertyMap( Property::Map& map ) const
index 1691888..31922ba 100644 (file)
@@ -129,6 +129,9 @@ void ColorVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Color Visual generated and ready to display
+  ResourceReady();
 }
 
 void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
index fbce369..b75b359 100644 (file)
@@ -278,6 +278,9 @@ void GradientVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Gradient Visual generated and ready to display
+  ResourceReady();
 }
 
 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
index 06a9601..27c91e2 100644 (file)
@@ -754,6 +754,9 @@ void ImageVisual::DoSetOnStage( Actor& actor )
   {
     actor.AddRenderer( mImpl->mRenderer );
     mPlacementActor.Reset();
+
+    // Image loaded and ready to display
+    ResourceReady();
   }
 }
 
@@ -925,6 +928,8 @@ void ImageVisual::UploadComplete( bool loadingSuccess, TextureSet textureSet, bo
         Image brokenImage = VisualFactoryCache::GetBrokenVisualImage();
         ApplyImageToSampler( brokenImage );
       }
+      // Image loaded and ready to display
+      ResourceReady();
     }
   }
   mTextureLoading = false;
index 190c457..76e8558 100644 (file)
@@ -518,6 +518,9 @@ void MeshVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Mesh loaded and ready to display
+  ResourceReady();
 }
 
 void MeshVisual::DoCreatePropertyMap( Property::Map& map ) const
index 36700fe..599546f 100644 (file)
@@ -317,6 +317,9 @@ void NPatchVisual::DoSetOnStage( Actor& actor )
   ApplyTextureAndUniforms();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // npatch loaded and ready to display
+  ResourceReady();
 }
 
 void NPatchVisual::DoSetOffStage( Actor& actor )
index 9d306be..ede8ce0 100644 (file)
@@ -418,6 +418,9 @@ void PrimitiveVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Primitive generated and ready to display
+  ResourceReady();
 }
 
 void PrimitiveVisual::DoCreatePropertyMap( Property::Map& map ) const
index 7fc1cf2..a1da87f 100644 (file)
@@ -228,6 +228,9 @@ void SvgVisual::ApplyRasterizedImage( PixelData rasterizedPixelData )
       // reset the weak handle so that the renderer only get added to actor once
       mPlacementActor.Reset();
     }
+
+   // Svg loaded and ready to display
+   ResourceReady();
   }
 }
 
index 77a680f..473abf5 100644 (file)
@@ -510,6 +510,9 @@ void TextVisual::UpdateRenderer( bool initializeRendererAndTexture )
       mImpl->mRenderer.SetTextures( textureSet );
 
       control.AddRenderer( mImpl->mRenderer );
+
+      // Text rendered and ready to display
+      ResourceReady();
     }
   }
 }
index f79afe6..4b14eca 100644 (file)
@@ -117,13 +117,15 @@ bool GetPolicyFromValue( const Property::Value& value, Vector2& policy )
 Internal::Visual::Base::Impl::Impl()
 : mCustomShader( NULL ),
   mBlendSlotDelegate( NULL ),
+  mResourceObserver( NULL ),
   mTransform(),
   mMixColor( Color::WHITE ),
   mControlSize( Vector2::ZERO ),
   mDepthIndex( 0.0f ),
   mMixColorIndex( Property::INVALID_INDEX ),
   mOpacityIndex( Property::INVALID_INDEX ),
-  mFlags( 0 )
+  mFlags( 0 ),
+  mResourceReady( false )
 {
 }
 
index 8b235f8..c31037f 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-resource-observer.h>
 #include <dali-toolkit/devel-api/align-enums.h>
 
 namespace Dali
@@ -115,6 +116,7 @@ struct Base::Impl
   Renderer        mRenderer;
   CustomShader*   mCustomShader;
   SlotDelegate<Visual::Base>* mBlendSlotDelegate; ///< Used to own mix color animation connection
+  ResourceObserver* mResourceObserver;  ///< Allows controls to observe when the visual resources are loaded and ready
   std::string     mName;
   Transform       mTransform;
   Vector4         mMixColor;
@@ -123,6 +125,7 @@ struct Base::Impl
   Property::Index mMixColorIndex;
   Property::Index mOpacityIndex;
   int             mFlags;
+  bool            mResourceReady:1;
 };
 
 } // namespace Visual
index c61aeba..275f569 100644 (file)
@@ -401,6 +401,37 @@ const Vector4& Visual::Base::GetMixColor() const
   return mImpl->mMixColor;
 }
 
+void Visual::Base::AddResourceObserver( Visual::ResourceObserver& observer)
+{
+  mImpl->mResourceObserver = &observer;
+}
+
+void Visual::Base::RemoveResourceObserver( Visual::ResourceObserver& observer )
+{
+  mImpl->mResourceObserver = NULL;
+}
+
+void Visual::Base::ResourceReady()
+{
+  if( mImpl->mResourceReady )
+  {
+    // only inform the observer the first time the resource is ready
+    return;
+  }
+  mImpl->mResourceReady = true;
+
+  if( mImpl->mResourceObserver )
+  {
+    // observer is currently a control impl
+    mImpl->mResourceObserver->ResourceReady( *this );
+  }
+}
+
+bool Visual::Base::IsResourceReady() const
+{
+  return mImpl->mResourceReady;
+}
+
 Renderer Visual::Base::GetRenderer()
 {
   return mImpl->mRenderer;
index ae8a35f..b671c15 100644 (file)
@@ -44,6 +44,8 @@ namespace Internal
 namespace Visual
 {
 
+class ResourceObserver;
+
 /**
  * Base class for all Control rendering logic. A control may have multiple visuals.
  *
@@ -208,6 +210,29 @@ public:
   void AnimateProperty( Dali::Animation& transition,
                         Internal::TransitionData::Animator& animator );
 
+  /**
+   * @brief Add an observer to watch for when the Visuals resources are loaded.
+   * Currently only supports a single observer
+   *
+   */
+  void AddResourceObserver( Visual::ResourceObserver& observer );
+
+  /**
+   * @brief Remove an observer
+   */
+  void RemoveResourceObserver( Visual::ResourceObserver& observer );
+
+  /**
+   * @brief Called when the visuals resources are loaded / ready
+   */
+  void ResourceReady();
+
+  /**
+   * @brief Called when the visuals resources are loaded / ready
+   * @return true if ready, false otherwise
+   */
+  bool IsResourceReady() const;
+
 protected:
 
   /**
diff --git a/dali-toolkit/internal/visuals/visual-resource-observer.h b/dali-toolkit/internal/visuals/visual-resource-observer.h
new file mode 100644 (file)
index 0000000..f671adc
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_INTERNAL_TOOLKIT_VISUAL_RESOURCE_OBSERVER_H
+#define DALI_INTERNAL_TOOLKIT_VISUAL_RESOURCE_OBSERVER_H
+
+/*
+ * Copyright (c) 2017 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.
+ */
+
+
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace Visual
+{
+
+class Base;
+
+
+/**
+ * Observer to be informed when a visuals resources are ready.
+ */
+class ResourceObserver
+{
+  public:
+
+    /**
+     * Inform the observer of the object that it's connections have changed
+     * @param[in] object The connection owner
+     */
+    virtual void ResourceReady( Visual::Base& object) = 0;
+
+  protected:
+
+    /**
+     * constructor
+     */
+    ResourceObserver()
+    {
+    };
+
+    /**
+     * virtual destructor
+     */
+    virtual ~ResourceObserver()
+    {
+    };
+
+    // Undefined copy constructor.
+    ResourceObserver( const ResourceObserver& );
+
+    // Undefined assignment operator.
+    ResourceObserver& operator=( const ResourceObserver& );
+};
+} // Visual
+} // Internal
+} // Toolkit
+} // Dali
+
+#endif // DALI_INTERNAL_TOOLKIT_VISUAL_RESOURCE_OBSERVER_H
index 990b25f..e674bf1 100644 (file)
@@ -174,6 +174,9 @@ void WireframeVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Wireframe generated and ready to display
+  ResourceReady();
 }
 
 void WireframeVisual::InitializeRenderer()
index fffbe69..525a02e 100644 (file)
 #include <stack>
 #include <typeinfo>
 #include <dali/public-api/animation/constraint.h>
-#include <dali/public-api/animation/constraints.h>
-#include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
-#include <dali/public-api/rendering/renderer.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
-#include <dali/devel-api/common/owner-container.h>
 #include <dali/devel-api/object/handle-devel.h>
-#include <dali/devel-api/scripting/enum-helper.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/debug.h>
 
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
-#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
-#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
-#include <dali-toolkit/internal/visuals/transition-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/devel-api/align-enums.h>
-#include <dali-toolkit/internal/controls/tooltip/tooltip.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
 namespace Dali
 {
@@ -63,19 +54,6 @@ namespace Toolkit
 namespace Internal
 {
 
-extern const Dali::Scripting::StringEnum ControlStateTable[];
-extern const unsigned int ControlStateTableCount;
-
-
-// Not static or anonymous - shared with other translation units
-const Scripting::StringEnum ControlStateTable[] = {
-  { "NORMAL",   Toolkit::DevelControl::NORMAL   },
-  { "FOCUSED",  Toolkit::DevelControl::FOCUSED  },
-  { "DISABLED", Toolkit::DevelControl::DISABLED },
-}; const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] );
-
-} // Internal namespace
-
 namespace
 {
 
@@ -89,23 +67,6 @@ DALI_ENUM_TO_STRING_WITH_SCOPE( ClippingMode, CLIP_CHILDREN )
 DALI_ENUM_TO_STRING_TABLE_END( CLIPPING_MODE )
 
 /**
- * Struct used to store Visual within the control, index is a unique key for each visual.
- */
-struct RegisteredVisual
-{
-  Property::Index index;
-  Toolkit::Visual::Base visual;
-  bool enabled;
-
-  RegisteredVisual( Property::Index aIndex, Toolkit::Visual::Base &aVisual, bool aEnabled)
-  : index(aIndex), visual(aVisual), enabled(aEnabled)
-  {
-  }
-};
-
-typedef Dali::OwnerContainer< RegisteredVisual* > RegisteredVisualContainer;
-
-/**
  *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
  */
 bool FindVisual( Property::Index targetIndex, RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
@@ -139,825 +100,9 @@ Toolkit::Visual::Base GetVisualByName(
   return visualHandle;
 }
 
-/**
- * Creates control through type registry
- */
-BaseHandle Create()
-{
-  return Internal::Control::New();
-}
-
-/**
- * Performs actions as requested using the action name.
- * @param[in] object The object on which to perform the action.
- * @param[in] actionName The action to perform.
- * @param[in] attributes The attributes with which to perfrom this action.
- * @return true if action has been accepted by this control
- */
-const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
-static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
-{
-  bool ret = false;
-
-  if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
-  {
-    Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
-    if( control )
-    {
-      // if cast succeeds there is an implementation so no need to check
-      ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
-    }
-  }
-
-  return ret;
-}
-
-/**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
-const char* SIGNAL_KEY_EVENT = "keyEvent";
-const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
-const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
-const char* SIGNAL_TAPPED = "tapped";
-const char* SIGNAL_PANNED = "panned";
-const char* SIGNAL_PINCHED = "pinched";
-const char* SIGNAL_LONG_PRESSED = "longPressed";
-static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
-{
-  Dali::BaseHandle handle( object );
-
-  bool connected( false );
-  Toolkit::Control control = Toolkit::Control::DownCast( handle );
-  if ( control )
-  {
-    Internal::Control& controlImpl( Internal::GetImplementation( control ) );
-    connected = true;
-
-    if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
-    {
-      controlImpl.KeyEventSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
-    {
-      controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
-    {
-      controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
-    {
-      controlImpl.EnableGestureDetection( Gesture::Tap );
-      controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
-    {
-      controlImpl.EnableGestureDetection( Gesture::Pan );
-      controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
-    {
-      controlImpl.EnableGestureDetection( Gesture::Pinch );
-      controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
-    }
-    else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
-    {
-      controlImpl.EnableGestureDetection( Gesture::LongPress );
-      controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
-    }
-  }
-  return connected;
-}
-
-// Setup signals and actions using the type-registry.
-DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
-
-// Note: Properties are registered separately below.
-
-SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
-SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
-SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
-SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
-SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
-SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
-SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
-
-TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
-
-DALI_TYPE_REGISTRATION_END()
-
 } // unnamed namespace
 
-namespace Internal
-{
-
-class Control::Impl : public ConnectionTracker
-{
-public:
-
-  // Construction & Destruction
-  Impl(Control& controlImpl)
-  : mControlImpl( controlImpl ),
-    mState( Toolkit::DevelControl::NORMAL ),
-    mSubStateName(""),
-    mLeftFocusableActorId( -1 ),
-    mRightFocusableActorId( -1 ),
-    mUpFocusableActorId( -1 ),
-    mDownFocusableActorId( -1 ),
-    mStyleName(""),
-    mBackgroundColor(Color::TRANSPARENT),
-    mStartingPinchScale( NULL ),
-    mKeyEventSignal(),
-    mPinchGestureDetector(),
-    mPanGestureDetector(),
-    mTapGestureDetector(),
-    mLongPressGestureDetector(),
-    mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
-    mIsKeyboardNavigationSupported( false ),
-    mIsKeyboardFocusGroup( false )
-  {
-  }
 
-  ~Impl()
-  {
-    // All gesture detectors will be destroyed so no need to disconnect.
-    delete mStartingPinchScale;
-  }
-
-  // Gesture Detection Methods
-
-  void PinchDetected(Actor actor, const PinchGesture& pinch)
-  {
-    mControlImpl.OnPinch(pinch);
-  }
-
-  void PanDetected(Actor actor, const PanGesture& pan)
-  {
-    mControlImpl.OnPan(pan);
-  }
-
-  void TapDetected(Actor actor, const TapGesture& tap)
-  {
-    mControlImpl.OnTap(tap);
-  }
-
-  void LongPressDetected(Actor actor, const LongPressGesture& longPress)
-  {
-    mControlImpl.OnLongPress(longPress);
-  }
-
-  // Properties
-
-  /**
-   * Called when a property of an object of this type is set.
-   * @param[in] object The object whose property is set.
-   * @param[in] index The property index.
-   * @param[in] value The new property value.
-   */
-  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
-  {
-    Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
-
-    if ( control )
-    {
-      Control& controlImpl( GetImplementation( control ) );
-
-      switch ( index )
-      {
-        case Toolkit::Control::Property::STYLE_NAME:
-        {
-          controlImpl.SetStyleName( value.Get< std::string >() );
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::STATE:
-        {
-          bool withTransitions=true;
-          const Property::Value* valuePtr=&value;
-          Property::Map* map = value.GetMap();
-          if(map)
-          {
-            Property::Value* value2 = map->Find("withTransitions");
-            if( value2 )
-            {
-              withTransitions = value2->Get<bool>();
-            }
-
-            valuePtr = map->Find("state");
-          }
-
-          if( valuePtr )
-          {
-            Toolkit::DevelControl::State state( controlImpl.mImpl->mState );
-            if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) )
-            {
-              controlImpl.mImpl->SetState( state, withTransitions );
-            }
-          }
-        }
-        break;
-
-        case Toolkit::DevelControl::Property::SUB_STATE:
-        {
-          std::string subState;
-          if( value.Get( subState ) )
-          {
-            controlImpl.mImpl->SetSubState( subState );
-          }
-        }
-        break;
-
-        case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
-        {
-          int focusId;
-          if( value.Get( focusId ) )
-          {
-            controlImpl.mImpl->mLeftFocusableActorId = focusId;
-          }
-        }
-        break;
-
-        case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
-        {
-          int focusId;
-          if( value.Get( focusId ) )
-          {
-            controlImpl.mImpl->mRightFocusableActorId = focusId;
-          }
-        }
-        break;
-
-        case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
-        {
-          int focusId;
-          if( value.Get( focusId ) )
-          {
-            controlImpl.mImpl->mUpFocusableActorId = focusId;
-          }
-        }
-        break;
-
-        case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
-        {
-          int focusId;
-          if( value.Get( focusId ) )
-          {
-            controlImpl.mImpl->mDownFocusableActorId = focusId;
-          }
-        }
-        break;
-
-        case Toolkit::Control::Property::BACKGROUND_COLOR:
-        {
-          DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
-          controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND_IMAGE:
-        {
-          DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
-          Image image = Scripting::NewImage( value );
-          if ( image )
-          {
-            controlImpl.SetBackgroundImage( image );
-          }
-          else
-          {
-            // An empty image means the background is no longer required
-            controlImpl.ClearBackground();
-          }
-          break;
-        }
-
-        case Toolkit::Control::Property::KEY_INPUT_FOCUS:
-        {
-          if ( value.Get< bool >() )
-          {
-            controlImpl.SetKeyInputFocus();
-          }
-          else
-          {
-            controlImpl.ClearKeyInputFocus();
-          }
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND:
-        {
-          std::string url;
-          Vector4 color;
-          const Property::Map* map = value.GetMap();
-          if( map && !map->Empty() )
-          {
-            controlImpl.SetBackground( *map );
-          }
-          else if( value.Get( url ) )
-          {
-            // don't know the size to load
-            Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
-            if( visual )
-            {
-              controlImpl.RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
-              visual.SetDepthIndex( DepthIndex::BACKGROUND );
-            }
-          }
-          else if( value.Get( color ) )
-          {
-            controlImpl.SetBackgroundColor(color);
-          }
-          else
-          {
-            // The background is an empty property map, so we should clear the background
-            controlImpl.ClearBackground();
-          }
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::TOOLTIP:
-        {
-          TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
-          if( ! tooltipPtr )
-          {
-            tooltipPtr = Tooltip::New( control );
-          }
-          tooltipPtr->SetProperties( value );
-        }
-      }
-    }
-  }
-
-  /**
-   * Called to retrieve a property of an object of this type.
-   * @param[in] object The object whose property is to be retrieved.
-   * @param[in] index The property index.
-   * @return The current value of the property.
-   */
-  static Property::Value GetProperty( BaseObject* object, Property::Index index )
-  {
-    Property::Value value;
-
-    Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
-
-    if ( control )
-    {
-      Control& controlImpl( GetImplementation( control ) );
-
-      switch ( index )
-      {
-        case Toolkit::Control::Property::STYLE_NAME:
-        {
-          value = controlImpl.GetStyleName();
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::STATE:
-        {
-          value = controlImpl.mImpl->mState;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::SUB_STATE:
-        {
-          value = controlImpl.mImpl->mSubStateName;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
-        {
-          value = controlImpl.mImpl->mLeftFocusableActorId;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
-        {
-          value = controlImpl.mImpl->mRightFocusableActorId;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
-        {
-          value = controlImpl.mImpl->mUpFocusableActorId;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
-        {
-          value = controlImpl.mImpl->mDownFocusableActorId;
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND_COLOR:
-        {
-          DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
-          value = controlImpl.GetBackgroundColor();
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND_IMAGE:
-        {
-          DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
-          Property::Map map;
-          Toolkit::Visual::Base visual = controlImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
-          if( visual )
-          {
-            visual.CreatePropertyMap( map );
-          }
-          value = map;
-          break;
-        }
-
-        case Toolkit::Control::Property::KEY_INPUT_FOCUS:
-        {
-          value = controlImpl.HasKeyInputFocus();
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND:
-        {
-          Property::Map map;
-          Toolkit::Visual::Base visual = controlImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
-          if( visual )
-          {
-            visual.CreatePropertyMap( map );
-          }
-
-          value = map;
-          break;
-        }
-
-        case Toolkit::DevelControl::Property::TOOLTIP:
-        {
-          Property::Map map;
-          if( controlImpl.mImpl->mTooltip )
-          {
-            controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
-          }
-          value = map;
-          break;
-        }
-
-      }
-    }
-
-    return value;
-  }
-
-
-  void CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
-  {
-    for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
-    {
-      if( (*iter)->visual )
-      {
-        Property::Map instanceMap;
-        Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
-        instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
-      }
-    }
-  }
-
-  template<typename T>
-  void Remove( Dictionary<T>& keyValues, const std::string& name )
-  {
-    keyValues.Remove(name);
-  }
-
-  void Remove( DictionaryKeys& keys, const std::string& name )
-  {
-    DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name );
-    if( iter != keys.end())
-    {
-      keys.erase(iter);
-    }
-  }
-
-  void FindChangableVisuals( Dictionary<Property::Map>& stateVisualsToAdd,
-                             Dictionary<Property::Map>& stateVisualsToChange,
-                             DictionaryKeys& stateVisualsToRemove)
-  {
-    DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
-
-    for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
-         iter != copyOfStateVisualsToRemove.end(); ++iter )
-    {
-      const std::string& visualName = (*iter);
-      Property::Map* toMap = stateVisualsToAdd.Find( visualName );
-      if( toMap )
-      {
-        stateVisualsToChange.Add( visualName, *toMap );
-        stateVisualsToAdd.Remove( visualName );
-        Remove( stateVisualsToRemove, visualName );
-      }
-    }
-  }
-
-  void RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
-  {
-    Actor self( mControlImpl.Self() );
-
-    for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
-          visualIter != visuals.End(); ++visualIter )
-    {
-      Toolkit::Visual::Base visual = (*visualIter)->visual;
-      if( visual && visual.GetName() == visualName )
-      {
-        Toolkit::GetImplementation(visual).SetOffStage( self );
-        (*visualIter)->visual.Reset();
-        visuals.Erase( visualIter );
-        break;
-      }
-    }
-  }
-
-  void RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
-  {
-    Actor self( mControlImpl.Self() );
-    for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
-    {
-      const std::string visualName = *iter;
-      RemoveVisual( visuals, visualName );
-    }
-  }
-
-  Toolkit::DevelVisual::Type GetVisualTypeFromMap( const Property::Map& map )
-  {
-    Property::Value* typeValue = map.Find( Toolkit::DevelVisual::Property::TYPE, VISUAL_TYPE  );
-    Toolkit::DevelVisual::Type type = Toolkit::DevelVisual::IMAGE;
-    if( typeValue )
-    {
-      Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type );
-    }
-    return type;
-  }
-
-  /**
-   * Go through the list of visuals that are common to both states.
-   * If they are different types, or are both image types with different
-   * URLs, then the existing visual needs moving and the new visual creating
-   */
-  void RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
-                               Dictionary<Property::Map>& instancedProperties )
-  {
-    Dali::CustomActor handle( mControlImpl.GetOwner() );
-    for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
-         iter != stateVisualsToChange.End(); ++iter )
-    {
-      const std::string& visualName = (*iter).key;
-      const Property::Map& toMap = (*iter).entry;
-
-      // is it a candidate for re-creation?
-      bool recreate = false;
-
-      Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
-      if( visual )
-      {
-        Property::Map fromMap;
-        visual.CreatePropertyMap( fromMap );
-
-        Toolkit::DevelVisual::Type fromType = GetVisualTypeFromMap( fromMap );
-        Toolkit::DevelVisual::Type toType = GetVisualTypeFromMap( toMap );
-
-        if( fromType != toType )
-        {
-          recreate = true;
-        }
-        else
-        {
-          if( fromType == Toolkit::DevelVisual::IMAGE || fromType == Toolkit::DevelVisual::N_PATCH
-              || fromType == Toolkit::DevelVisual::SVG || fromType == Toolkit::DevelVisual::ANIMATED_IMAGE )
-          {
-            Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
-            Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
-
-            if( fromUrl && toUrl )
-            {
-              std::string fromUrlString;
-              std::string toUrlString;
-              fromUrl->Get(fromUrlString);
-              toUrl->Get(toUrlString);
-
-              if( fromUrlString != toUrlString )
-              {
-                recreate = true;
-              }
-            }
-          }
-        }
-
-        const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
-        if( recreate || instancedMap )
-        {
-          RemoveVisual( mVisuals, visualName );
-          Style::ApplyVisual( handle, visualName, toMap, instancedMap );
-        }
-        else
-        {
-          // @todo check to see if we can apply toMap without recreating the visual
-          // e.g. by setting only animatable properties
-          // For now, recreate all visuals, but merge in instance data.
-          RemoveVisual( mVisuals, visualName );
-          Style::ApplyVisual( handle, visualName, toMap, instancedMap );
-        }
-      }
-    }
-  }
-
-  void ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
-  {
-    // Collect all old visual names
-    DictionaryKeys stateVisualsToRemove;
-    if( oldState )
-    {
-      oldState->visuals.GetKeys( stateVisualsToRemove );
-      if( ! subState.empty() )
-      {
-        const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
-        if( oldSubState )
-        {
-          DictionaryKeys subStateVisualsToRemove;
-          (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
-          Merge( stateVisualsToRemove, subStateVisualsToRemove );
-        }
-      }
-    }
-
-    // Collect all new visual properties
-    Dictionary<Property::Map> stateVisualsToAdd;
-    if( newState )
-    {
-      stateVisualsToAdd = newState->visuals;
-      if( ! subState.empty() )
-      {
-        const StylePtr* newSubState = newState->subStates.FindConst(subState);
-        if( newSubState )
-        {
-          stateVisualsToAdd.Merge( (*newSubState)->visuals );
-        }
-      }
-    }
-
-    // If a name is in both add/remove, move it to change list.
-    Dictionary<Property::Map> stateVisualsToChange;
-    FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
-
-    // Copy instanced properties (e.g. text label) of current visuals
-    Dictionary<Property::Map> instancedProperties;
-    CopyInstancedProperties( mVisuals, instancedProperties );
-
-    // For each visual in remove list, remove from mVisuals
-    RemoveVisuals( mVisuals, stateVisualsToRemove );
-
-    // For each visual in add list, create and add to mVisuals
-    Dali::CustomActor handle( mControlImpl.GetOwner() );
-    Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
-
-    // For each visual in change list, if it requires a new visual,
-    // remove old visual, create and add to mVisuals
-    RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
-  }
-
-  void SetState( DevelControl::State newState, bool withTransitions=true )
-  {
-    DevelControl::State oldState = mState;
-    Dali::CustomActor handle( mControlImpl.GetOwner() );
-    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
-                  (mState == DevelControl::NORMAL ? "NORMAL" :(
-                    mState == DevelControl::FOCUSED ?"FOCUSED" : (
-                      mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
-
-    if( mState != newState )
-    {
-      // If mState was Disabled, and new state is Focused, should probably
-      // store that fact, e.g. in another property that FocusManager can access.
-      mState = newState;
-
-      // Trigger state change and transitions
-      // Apply new style, if stylemanager is available
-      Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
-      if( styleManager )
-      {
-        const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
-
-        if( stylePtr )
-        {
-          std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
-          std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
-
-          const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
-          const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
-          if( oldStateStyle && newStateStyle )
-          {
-            // Only change if both state styles exist
-            ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
-          }
-        }
-      }
-    }
-  }
-
-  void SetSubState( const std::string& subStateName, bool withTransitions=true )
-  {
-    if( mSubStateName != subStateName )
-    {
-      // Get existing sub-state visuals, and unregister them
-      Dali::CustomActor handle( mControlImpl.GetOwner() );
-
-      Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
-      if( styleManager )
-      {
-        const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
-        if( stylePtr )
-        {
-          // Stringify state
-          std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount );
-
-          const StylePtr* state = stylePtr->subStates.Find( stateName );
-          if( state )
-          {
-            StylePtr stateStyle(*state);
-
-            const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
-            const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
-            if( oldStateStyle && newStateStyle )
-            {
-              std::string empty;
-              ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
-            }
-          }
-        }
-      }
-
-      mSubStateName = subStateName;
-    }
-  }
-
-  // Data
-
-  Control& mControlImpl;
-  DevelControl::State mState;
-  std::string mSubStateName;
-
-  int mLeftFocusableActorId;       ///< Actor ID of Left focusable control.
-  int mRightFocusableActorId;      ///< Actor ID of Right focusable control.
-  int mUpFocusableActorId;         ///< Actor ID of Up focusable control.
-  int mDownFocusableActorId;       ///< Actor ID of Down focusable control.
-
-  RegisteredVisualContainer mVisuals; // Stores visuals needed by the control, non trivial type so std::vector used.
-  std::string mStyleName;
-  Vector4 mBackgroundColor;                       ///< The color of the background visual
-  Vector3* mStartingPinchScale;      ///< The scale when a pinch gesture starts, TODO: consider removing this
-  Toolkit::Control::KeyEventSignalType mKeyEventSignal;
-  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusGainedSignal;
-  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusLostSignal;
-
-  // Gesture Detection
-  PinchGestureDetector mPinchGestureDetector;
-  PanGestureDetector mPanGestureDetector;
-  TapGestureDetector mTapGestureDetector;
-  LongPressGestureDetector mLongPressGestureDetector;
-
-  // Tooltip
-  TooltipPtr mTooltip;
-
-  ControlBehaviour mFlags : CONTROL_BEHAVIOUR_FLAG_COUNT;    ///< Flags passed in from constructor.
-  bool mIsKeyboardNavigationSupported :1;  ///< Stores whether keyboard navigation is supported by the control.
-  bool mIsKeyboardFocusGroup :1;           ///< Stores whether the control is a focus group.
-
-  // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
-  static const PropertyRegistration PROPERTY_1;
-  static const PropertyRegistration PROPERTY_2;
-  static const PropertyRegistration PROPERTY_3;
-  static const PropertyRegistration PROPERTY_4;
-  static const PropertyRegistration PROPERTY_5;
-  static const PropertyRegistration PROPERTY_6;
-  static const PropertyRegistration PROPERTY_7;
-  static const PropertyRegistration PROPERTY_8;
-  static const PropertyRegistration PROPERTY_9;
-  static const PropertyRegistration PROPERTY_10;
-  static const PropertyRegistration PROPERTY_11;
-  static const PropertyRegistration PROPERTY_12;
-};
-
-// Properties registered without macro to use specific member variables.
-const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName",              Toolkit::Control::Property::STYLE_NAME,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgroundColor",        Toolkit::Control::Property::BACKGROUND_COLOR,             Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage",        Toolkit::Control::Property::BACKGROUND_IMAGE,             Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",          Toolkit::Control::Property::KEY_INPUT_FOCUS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",             Toolkit::Control::Property::BACKGROUND,                   Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "tooltip",                Toolkit::DevelControl::Property::TOOLTIP,                 Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "state",                  Toolkit::DevelControl::Property::STATE,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "subState",               Toolkit::DevelControl::Property::SUB_STATE,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "leftFocusableActorId",   Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "upFocusableActorId",    Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,   Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "downFocusableActorId",  Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
 
 Toolkit::Control Control::New()
 {
@@ -1204,6 +349,10 @@ void Control::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visu
       {
         Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
       }
+
+      mImpl->StopObservingVisual( (*iter)->visual );
+      mImpl->StartObservingVisual( visual );
+
       (*iter)->visual = visual;
       visualReplaced = true;
     }
@@ -1233,6 +382,10 @@ void Control::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visu
   if( !visualReplaced ) // New registration entry
   {
     mImpl->mVisuals.PushBack( new RegisteredVisual( index, visual, enabled ) );
+
+    // monitor when the visuals resources are ready
+    mImpl->StartObservingVisual( visual );
+
   }
 
   if( visual && self.OnStage() && enabled )
@@ -1248,6 +401,9 @@ void Control::UnregisterVisual( Property::Index index )
    RegisteredVisualContainer::Iterator iter;
    if ( FindVisual( index, mImpl->mVisuals, iter ) )
    {
+     // stop observing visual
+     mImpl->StopObservingVisual( (*iter)->visual );
+
      Actor self( Self() );
      Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
      (*iter)->visual.Reset();
index 45eff9f..7b81c67 100644 (file)
@@ -774,7 +774,10 @@ private:
   DALI_INTERNAL Control( const Control& );
   DALI_INTERNAL Control& operator=( const Control& );
 
-  class Impl;
+public:
+  class Impl; // Class declaration is public so we can internally add devel API's to the Controls Impl
+
+private:
   Impl* mImpl;
   /// @endcond