[3.0] Resource ready signal for Controls (for ImageLoading) 24/131924/13
authorNick Holland <nick.holland@partner.samsung.com>
Wed, 31 May 2017 08:21:24 +0000 (09:21 +0100)
committerNick Holland <nick.holland@partner.samsung.com>
Fri, 16 Jun 2017 09:58:07 +0000 (09:58 +0000)
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
Add RegisterVisual + allow the control to store a list of visuals

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.

Example to test change:
https://review.tizen.org/gerrit/#/c/132789

Change-Id: I60ebccb4ea257165a1fa1dd33ac23233f8762638

25 files changed:
dali-toolkit/devel-api/controls/control-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/control-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/visual-factory/visual-base.cpp
dali-toolkit/devel-api/visual-factory/visual-base.h
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/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/file.list
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/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

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..ba3099b
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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();
+}
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual )
+{
+  Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
+  controlImpl.RegisterVisual( index, visual );
+}
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
+{
+  Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
+  controlImpl.RegisterVisual( index, visual, enabled );
+}
+
+void UnregisterVisual( Internal::Control& control, Dali::Property::Index index )
+{
+  Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
+  controlImpl.UnregisterVisual( index );
+}
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/control-devel.h b/dali-toolkit/devel-api/controls/control-devel.h
new file mode 100644 (file)
index 0000000..d113632
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_TOOLKIT_CONTROL_DEVEL_H
+#define DALI_TOOLKIT_CONTROL_DEVEL_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class TransitionData;
+
+namespace Visual
+{
+class Base;
+}
+
+namespace DevelControl
+{
+
+
+/// @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
+ */
+DALI_IMPORT_API 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
+ *
+ */
+DALI_IMPORT_API bool IsResourceReady( const Control& control );
+
+/**
+ * @brief Register a visual by Property Index, linking an Actor to visual when required.
+ * In the case of the visual being an actor or control deeming visual not required then visual should be an empty handle.
+ * No parenting is done during registration, this should be done by derived class.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ * @note Derived class should not call visual.SetOnStage(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
+ *       Use below API with enabled set to false if derived class wishes to control when visual is staged.
+ */
+DALI_IMPORT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual );
+
+/**
+ * @brief Register a visual by Property Index, linking an Actor to visual when required.
+ *
+ * In the case of the visual being an actor or control deeming visual not required then visual should be an empty handle.
+ * If enabled is false then the visual is not set on stage until enabled by the derived class.
+ * @see EnableVisual
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ * @param[in] enabled false if derived class wants to control when visual is set on stage.
+ *
+ */
+DALI_IMPORT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled );
+
+/**
+ * @brief Erase the entry matching the given index from the list of registered visuals
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ */
+DALI_IMPORT_API void UnregisterVisual( Internal::Control& control, Dali::Property::Index index );
+
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DEVEL_H
index 77ee5c6..b47a3d4 100755 (executable)
@@ -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/bloom-view/bloom-view.cpp \
   $(devel_api_src_dir)/controls/bubble-effect/bubble-emitter.cpp \
   $(devel_api_src_dir)/controls/effects-view/effects-view.cpp \
@@ -33,7 +34,8 @@ devel_api_src_files = \
 # Add devel header files here
 
 devel_api_controls_header_files = \
-  $(devel_api_src_dir)/controls/control-depth-index-ranges.h
+  $(devel_api_src_dir)/controls/control-depth-index-ranges.h \
+  $(devel_api_src_dir)/controls/control-devel.h
 
 devel_api_bloom_view_header_files = \
   $(devel_api_src_dir)/controls/bloom-view/bloom-view.h
index 0b3193f..5a3230d 100644 (file)
@@ -54,6 +54,16 @@ Base::Base(Internal::Visual::Base *impl)
 {
 }
 
+void Visual::Base::SetName( const std::string& name )
+{
+  GetImplementation( *this ).SetName( name );
+}
+
+const std::string& Visual::Base::GetName()
+{
+  return GetImplementation( *this ).GetName();
+}
+
 void Base::SetSize( const Vector2& size )
 {
   GetImplementation( *this ).SetSize( size );
index 74ca640..d58d168 100644 (file)
@@ -90,6 +90,21 @@ public:
   const Vector2& GetSize() const;
 
   /**
+   * @brief Set the name of the visual
+   *
+   * Used by the styling system to animate properties
+   * @param[in] name The name to give the visual
+   */
+  void SetName( const std::string& name );
+
+  /**
+   * @brief Get the name of the visual
+   *
+   * Used by the styling system to animate properties
+   * @return The name of the visual
+   */
+  const std::string& GetName();
+  /**
    * @brief Return the natural size of the visual.
    *
    * Deriving classes stipulate the natural size and by default a visual has a ZERO natural size.
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..fb2cf4e
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * 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
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+/**
+ *  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, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
+{
+  for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
+  {
+    if ( (*iter)->index ==  targetIndex )
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+
+
+/**
+ * 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 );
+
+
+
+Control::Impl::Impl( Control& controlImpl )
+: mControlImpl( controlImpl ),
+  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;
+}
+
+// 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::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
+{
+  RegisterVisual( index, visual, true );
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
+{
+  bool visualReplaced ( false );
+  Actor self = mControlImpl.Self();
+
+  if( !mVisuals.Empty() )
+  {
+    RegisteredVisualContainer::Iterator iter;
+    // Check if visual (index) is already registered.  Replace if so.
+    if ( FindVisual( index, mVisuals, iter ) )
+    {
+      if( (*iter)->visual && self.OnStage() )
+      {
+        Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
+      }
+
+      StopObservingVisual( (*iter)->visual );
+      StartObservingVisual( visual );
+
+      (*iter)->visual = visual;
+      visualReplaced = true;
+    }
+  }
+
+  if( !visualReplaced ) // New registration entry
+  {
+    mVisuals.PushBack( new RegisteredVisual( index, visual, enabled ) );
+
+    // monitor when the visuals resources are ready
+    StartObservingVisual( visual );
+
+  }
+
+  if( visual && self.OnStage() && enabled )
+  {
+    Toolkit::GetImplementation(visual).SetOnStage( self );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"T":"F" );
+}
+
+void Control::Impl::UnregisterVisual( Property::Index index )
+{
+   RegisteredVisualContainer::Iterator iter;
+   if ( FindVisual( index, mVisuals, iter ) )
+   {
+     // stop observing visual
+     StopObservingVisual( (*iter)->visual );
+
+     Actor self( mControlImpl.Self() );
+     Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
+     (*iter)->visual.Reset();
+     mVisuals.Erase( iter );
+   }
+}
+
+Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    return (*iter)->visual;
+  }
+
+  return Toolkit::Visual::Base();
+}
+
+void Control::Impl::EnableVisual( Property::Index index, bool enable )
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    if (  (*iter)->enabled == enable )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
+      return;
+    }
+
+    (*iter)->enabled = enable;
+    Actor parentActor = mControlImpl.Self();
+    if ( mControlImpl.Self().OnStage() ) // If control not on Stage then Visual will be added when StageConnection is called.
+    {
+      if ( enable )
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
+        Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor );
+      }
+      else
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
+        Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor );  // No need to call if control not staged.
+      }
+    }
+  }
+}
+
+bool Control::Impl::IsVisualEnabled( Property::Index index ) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    return (*iter)->enabled;
+  }
+  return false;
+}
+
+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 );
+}
+
+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::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.mImpl->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;
+      }
+    }
+  }
+}
+
+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::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.mImpl->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.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+
+        value = map;
+        break;
+      }
+
+    }
+  }
+
+  return value;
+}
+
+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;
+    }
+  }
+}
+
+} // 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..800bda1
--- /dev/null
@@ -0,0 +1,234 @@
+#ifndef DALI_TOOLKIT_CONTROL_DATA_IMPL_H
+#define DALI_TOOLKIT_CONTROL_DATA_IMPL_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.
+ *
+ */
+
+// 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>
+
+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;
+
+
+/**
+ * @brief Holds the Implementation for the internal control class
+ */
+class Control::Impl : public ConnectionTracker, public Visual::ResourceObserver
+{
+
+public:
+
+  /**
+   * @brief Retrieves the implementation of the internal control class.
+   * @param[in] internalControl A ref to the control whose internal implementation is required
+   * @return The internal implementation
+   */
+  static Control::Impl& Get( Internal::Control& internalControl );
+
+  /**
+   * @copydoc Get( Internal::Control& )
+   */
+  static const Control::Impl& Get( const Internal::Control& internalControl );
+
+  /**
+   * @brief Constructor.
+   * @param[in] controlImpl The control which own this implementation
+   */
+  Impl( Control& controlImpl );
+
+  /**
+   * @brief Destructor.
+   */
+  ~Impl();
+
+  /**
+   * @brief Called when a pinch is detected.
+   * @param[in] actor The actor the pinch occurred on
+   * @param[in] pinch The pinch gesture details
+   */
+  void PinchDetected(Actor actor, const PinchGesture& pinch);
+
+  /**
+   * @brief Called when a pan is detected.
+   * @param[in] actor The actor the pan occurred on
+   * @param[in] pan The pan gesture details
+   */
+  void PanDetected(Actor actor, const PanGesture& pan);
+
+  /**
+   * @brief Called when a tap is detected.
+   * @param[in] actor The actor the tap occurred on
+   * @param[in] tap The tap gesture details
+   */
+  void TapDetected(Actor actor, const TapGesture& tap);
+
+  /**
+   * @brief Called when a long-press is detected.
+   * @param[in] actor The actor the long-press occurred on
+   * @param[in] longPress The long-press gesture details
+   */
+  void LongPressDetected(Actor actor, const LongPressGesture& longPress);
+
+  /**
+   * @brief Called when a resource is ready.
+   * @param[in] object The visual whose resources are ready
+   * @note Overriding method in Visual::ResourceObserver.
+   */
+  virtual void ResourceReady( Visual::Base& object );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::UnregisterVisual()
+   */
+  void UnregisterVisual( Property::Index index );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::GetVisual()
+   */
+  Toolkit::Visual::Base GetVisual( Property::Index index ) const;
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::EnableVisual()
+   */
+  void EnableVisual( Property::Index index, bool enable );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::IsVisualEnabled()
+   */
+  bool IsVisualEnabled( Property::Index index ) const;
+
+  /**
+   * @brief Stops observing the given visual.
+   * @param[in] visual The visual to stop observing
+   */
+  void StopObservingVisual( Toolkit::Visual::Base& visual );
+
+  /**
+   * @brief Starts observing the given visual.
+   * @param[in] visual The visual to start observing
+   */
+  void StartObservingVisual( Toolkit::Visual::Base& visual);
+
+  /**
+   * @brief Function used to set control properties.
+   * @param[in] object The object whose property to set
+   * @param[in] index The index of the property to set
+   * @param[in] value The value of the property to set
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Function used to retrieve the value of control properties.
+   * @param[in] object The object whose property to get
+   * @param[in] index The index of the property to get
+   * @return The value of the property
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @brief Removes a visual from the control's container.
+   * @param[in] visuals The container of visuals
+   * @param[in] visualName The name of the visual to remove
+   */
+  void RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName );
+
+  /**
+   * @brief Whether the resource is ready
+   * @return True if the resource is read.
+   */
+  bool IsResourceReady() const;
+
+  Control& mControlImpl;
+
+  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;
+
+  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;
+
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DATA_IMPL_H
index 6ee7a52..8b26127 100644 (file)
@@ -15,6 +15,7 @@
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 
 namespace Dali
 {
@@ -83,6 +84,7 @@ void ImageView::SetImage( Image image )
 
     Actor self( Self() );
     InitializeVisual( self, mVisual, image );
+    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual  );
     mImageSize = image ? ImageDimensions( image.GetWidth(), image.GetHeight() ) : ImageDimensions( 0, 0 );
 
     RelayoutRequest();
@@ -97,6 +99,7 @@ void ImageView::SetImage( Property::Map map )
 
   Actor self( Self() );
   InitializeVisual( self, mVisual, mPropertyMap );
+  DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual  );
 
   Property::Value* widthValue = mPropertyMap.Find( "width" );
   if( widthValue )
@@ -139,6 +142,7 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size )
 
     Actor self( Self() );
     InitializeVisual( self, mVisual, url, size );
+    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual  );
 
     mVisual.SetSize( mSizeSet );
 
index 3488b4c..02d1373 100644 (file)
@@ -37,6 +37,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/buttons/check-box-button-impl.cpp \
    $(toolkit_src_dir)/controls/buttons/push-button-impl.cpp \
    $(toolkit_src_dir)/controls/buttons/radio-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 8718bce..9493651 100644 (file)
@@ -156,6 +156,9 @@ void BorderVisual::DoSetOnStage( Actor& actor )
   mBorderSizeIndex = (mImpl->mRenderer).RegisterProperty( SIZE_NAME, mBorderSize );
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // Border Visual Generated and ready to display
+  ResourceReady();
 }
 
 void BorderVisual::DoCreatePropertyMap( Property::Map& map ) const
index 32a7e93..25eef2d 100644 (file)
@@ -108,6 +108,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 8afdb1e..2c1b4bb 100644 (file)
@@ -246,6 +246,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 f3d4feb..2f00a3c 100644 (file)
@@ -433,6 +433,7 @@ Image ImageVisual::LoadImage( const std::string& url, bool synchronousLoading )
   }
   else
   {
+    // Asynchronous image load
     ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode );
     resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded );
     return resourceImage;
@@ -467,6 +468,7 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin
   }
   else
   {
+    // Asynchronous image load
     textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, url, mDesiredSize, mFittingMode, true, this );
     mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
     if( !textureSet ) // big image, no atlasing
@@ -586,6 +588,9 @@ void ImageVisual::UploadCompleted()
     // reset the weak handle so that the renderer only get added to actor once
     mPlacementActor.Reset();
   }
+
+  // Image async loaded into the Atlas and is ready to display
+  ResourceReady();
 }
 
 void ImageVisual::DoSetOnStage( Actor& actor )
@@ -605,6 +610,9 @@ void ImageVisual::DoSetOnStage( Actor& actor )
   {
     actor.AddRenderer( mImpl->mRenderer );
     mPlacementActor.Reset();
+
+    // If we're sync loading and not atlasing (async), then the resource is ready to display
+    ResourceReady();
   }
 }
 
@@ -847,6 +855,8 @@ void ImageVisual::OnImageLoaded( ResourceImage image )
       ApplyImageToSampler( brokenImage );
     }
   }
+  // ResourceImage async loaded and ready to display
+  ResourceReady();
 }
 
 void ImageVisual::CleanCache(const std::string& url)
index d16be55..4b9f5ae 100644 (file)
@@ -386,6 +386,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 8a8b632..39c7960 100644 (file)
@@ -392,6 +392,9 @@ void NPatchVisual::DoSetOnStage( Actor& actor )
   }
 
   actor.AddRenderer( mImpl->mRenderer );
+
+  // npatch loaded and ready to display
+  ResourceReady();
 }
 
 void NPatchVisual::DoSetOffStage( Actor& actor )
index 841f507..0832474 100644 (file)
@@ -397,6 +397,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 f1658f1..bf3c8e0 100644 (file)
@@ -250,6 +250,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 f539dd6..fe3ce59 100644 (file)
@@ -50,8 +50,10 @@ DALI_ENUM_TO_STRING_TABLE_END( SHADER_HINT )
 
 Internal::Visual::Base::Impl::Impl()
 : mCustomShader(NULL),
+  mResourceObserver( NULL ),
   mDepthIndex( 0.0f ),
-  mFlags( 0 )
+  mFlags( 0 ),
+  mResourceReady( false )
 {
 }
 
index fb8ae32..9389f93 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>
 
 namespace Dali
 {
@@ -64,11 +65,13 @@ struct Base::Impl
 
   CustomShader* mCustomShader;
 
+  ResourceObserver* mResourceObserver;  ///< Allows controls to observe when the visual resources are loaded and ready
+  std::string     mName;
   Vector2   mSize;
   Vector2   mOffset;
   float     mDepthIndex;
   int       mFlags;
-
+  bool            mResourceReady:1;
   Impl();
   ~Impl();
 };
index 8010118..11e6e4c 100644 (file)
@@ -99,6 +99,16 @@ const Vector2& Base::GetSize() const
   return mImpl->mSize;
 }
 
+void Base::SetName( const std::string& name )
+{
+  mImpl->mName = name;
+}
+
+const std::string& Base::GetName() const
+{
+  return mImpl->mName;
+}
+
 void Base::GetNaturalSize( Vector2& naturalSize ) const
 {
   naturalSize = Vector2::ZERO;
@@ -176,6 +186,41 @@ void Base::DoSetOffStage( Actor& actor )
   mImpl->mRenderer.Reset();
 }
 
+
+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;
+  }
+
+
+  if( mImpl->mResourceObserver )
+  {
+    mImpl->mResourceReady = true;
+
+    // observer is currently a control impl
+    mImpl->mResourceObserver->ResourceReady( *this );
+  }
+}
+
+bool Visual::Base::IsResourceReady() const
+{
+  return mImpl->mResourceReady;
+}
+
 void Base::CreatePropertyMap( Property::Map& map ) const
 {
   DoCreatePropertyMap( map );
index aa80c03..1300347 100644 (file)
@@ -40,6 +40,8 @@ namespace Internal
 namespace Visual
 {
 
+class ResourceObserver;
+
 /**
  * Base class for all Control rendering logic. A control may have multiple visuals.
  *
@@ -85,6 +87,16 @@ public:
   const Vector2& GetSize() const;
 
   /**
+   * @copydoc Toolkit::Visual::Base::SetName
+   */
+  void SetName( const std::string& name );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetName
+   */
+  const std::string& GetName() const;
+
+  /**
    * @copydoc Toolkit::Visual::Base::GetNaturalSize
    */
   virtual void GetNaturalSize( Vector2& naturalSize ) const;
@@ -154,6 +166,29 @@ public:
    */
   void SetCustomShader( const Property::Map& propertyMap );
 
+  /**
+   * @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 4299eb6..f86dff2 100644 (file)
@@ -78,6 +78,8 @@ void WireframeVisual::DoSetOnStage( Actor& actor )
   InitializeRenderer();
 
   actor.AddRenderer( mImpl->mRenderer );
+  // Wireframe generated and ready to display
+  ResourceReady();
 }
 
 void WireframeVisual::DoCreatePropertyMap( Property::Map& map ) const
index 9bf179f..2bec2a1 100644 (file)
@@ -44,6 +44,7 @@
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
 namespace Dali
 {
@@ -51,357 +52,18 @@ namespace Dali
 namespace Toolkit
 {
 
-namespace
-{
-
-/**
- * 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 ),
-  mStyleName(""),
-  mBackgroundVisual(),
-  mBackgroundColor(Color::TRANSPARENT),
-  mStartingPinchScale( NULL ),
-  mKeyEventSignal(),
-  mPinchGestureDetector(),
-  mPanGestureDetector(),
-  mTapGestureDetector(),
-  mLongPressGestureDetector(),
-  mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
-  mIsKeyboardNavigationSupported( false ),
-  mIsKeyboardFocusGroup( false )
+namespace
 {
-}
-
-  ~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);
-  }
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
 
-  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::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 map 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:
-        {
-          const Property::Map* map = value.GetMap();
-          if( map )
-          {
-            controlImpl.SetBackground( *map );
-          }
-          else
-          {
-            // The background is not a property map, so we should clear the background
-            controlImpl.ClearBackground();
-          }
-          break;
-        }
-      }
-    }
-  }
-
-  /**
-   * 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::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;
-          if( controlImpl.mImpl->mBackgroundVisual )
-          {
-            controlImpl.mImpl->mBackgroundVisual.CreatePropertyMap( map );
-          }
-          value = map;
-          break;
-        }
-
-        case Toolkit::Control::Property::KEY_INPUT_FOCUS:
-        {
-          value = controlImpl.HasKeyInputFocus();
-          break;
-        }
-
-        case Toolkit::Control::Property::BACKGROUND:
-        {
-          Property::Map map;
-          if( controlImpl.mImpl->mBackgroundVisual )
-          {
-            (controlImpl.mImpl->mBackgroundVisual).CreatePropertyMap( map );
-          }
-
-          value = map;
-          break;
-        }
-
-      }
-    }
-
-    return value;
-  }
+} // unnamed namespace
 
-  // Data
-
-  Control& mControlImpl;
-  std::string mStyleName;
-  Toolkit::Visual::Base mBackgroundVisual;   ///< The visual to render the background
-  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;
-
-  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 need to function within this class.
-  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;
-};
-
-// 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 );
 
 Toolkit::Control Control::New()
 {
@@ -440,16 +102,12 @@ const std::string& Control::GetStyleName() const
 
 void Control::SetBackgroundColor( const Vector4& color )
 {
-  Actor self( Self() );
   mImpl->mBackgroundColor = color;
   Property::Map map;
   map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
   map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
-  InitializeVisual( self, mImpl->mBackgroundVisual, map );
-  if( mImpl->mBackgroundVisual )
-  {
-    mImpl->mBackgroundVisual.SetDepthIndex( DepthIndex::BACKGROUND );
-  }
+
+  SetBackground( map );
 }
 
 Vector4 Control::GetBackgroundColor() const
@@ -459,47 +117,34 @@ Vector4 Control::GetBackgroundColor() const
 
 void Control::SetBackground( const Property::Map& map )
 {
-  Actor self( Self() );
-  Toolkit::Visual::Base backgroundVisual = Toolkit::VisualFactory::Get().CreateVisual( map );
-
-  // if new visual created, replace existing one
-  if( backgroundVisual )
-  {
-    if( self.OnStage() )
-    {
-      mImpl->mBackgroundVisual.RemoveAndReset( self );
-      backgroundVisual.SetOnStage( self );
-    }
-    mImpl->mBackgroundVisual = backgroundVisual;
-    mImpl->mBackgroundVisual.SetDepthIndex( DepthIndex::BACKGROUND );
-  }
-  // ...otherwise process map and apply it to the existing visual
-  else if( mImpl->mBackgroundVisual )
+  Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
+  if( visual )
   {
-    Property::Value* premultipliedAlpha = map.Find( Toolkit::DevelVisual::Property::PREMULTIPLIED_ALPHA, Toolkit::Internal::PREMULTIPLIED_ALPHA );
-    if( premultipliedAlpha )
-    {
-      bool value( premultipliedAlpha->Get<bool>() );
-      Toolkit::GetImplementation( mImpl->mBackgroundVisual ).EnablePreMultipliedAlpha( value );
-    }
+    mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
+    visual.SetDepthIndex( DepthIndex::BACKGROUND );
+
+    // Trigger a size negotiation request that may be needed by the new visual to relayout its contents.
+    RelayoutRequest();
   }
 }
 
 void Control::SetBackgroundImage( Image image )
 {
-  Actor self( Self() );
-  InitializeVisual( self, mImpl->mBackgroundVisual, image );
-  if( mImpl->mBackgroundVisual )
+  Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( image );
+  if( visual )
   {
-    mImpl->mBackgroundVisual.SetDepthIndex( DepthIndex::BACKGROUND );
+    mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
+    visual.SetDepthIndex( DepthIndex::BACKGROUND );
   }
 }
 
 void Control::ClearBackground()
 {
-  Actor self( Self() );
-  mImpl->mBackgroundVisual.RemoveAndReset( self );
-  mImpl->mBackgroundColor = Color::TRANSPARENT;
+   mImpl->UnregisterVisual( Toolkit::Control::Property::BACKGROUND );
+   mImpl->mBackgroundColor = Color::TRANSPARENT;
+
+   // Trigger a size negotiation request that may be needed when unregistering a visual.
+   RelayoutRequest();
 }
 
 void Control::EnableGestureDetection(Gesture::Type type)
@@ -832,19 +477,48 @@ void Control::EmitKeyInputFocusSignal( bool focusGained )
 
 void Control::OnStageConnection( int depth )
 {
-  if( mImpl->mBackgroundVisual)
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection number of registered visuals(%d)\n",  mImpl->mVisuals.Size() );
+
+  Actor self( Self() );
+
+  for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter!= mImpl->mVisuals.End(); iter++)
   {
-    Actor self( Self() );
-    mImpl->mBackgroundVisual.SetOnStage( self );
+    // Check whether the visual is empty and enabled
+    if( (*iter)->visual && (*iter)->enabled )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection Setting visual(%d) on stage\n", (*iter)->index );
+      Toolkit::GetImplementation((*iter)->visual).SetOnStage( self );
+    }
+  }
+
+  if( mImpl->mVisuals.Empty() && ! self.GetRendererCount() )
+  {
+    Property::Value clippingValue = self.GetProperty( Actor::Property::CLIPPING_MODE );
+    int clippingMode = ClippingMode::DISABLED;
+    if( clippingValue.Get( clippingMode ) )
+    {
+      // Add a transparent background if we do not have any renderers or visuals so we clip our children
+
+      if( clippingMode == ClippingMode::CLIP_CHILDREN )
+      {
+        // Create a transparent background visual which will also get staged.
+        SetBackgroundColor( Color::TRANSPARENT );
+      }
+    }
   }
 }
 
 void Control::OnStageDisconnection()
 {
-  if( mImpl->mBackgroundVisual )
+  for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter!= mImpl->mVisuals.End(); iter++)
   {
-    Actor self( Self() );
-    mImpl->mBackgroundVisual.SetOffStage( self );
+    // Check whether the visual is empty
+    if( (*iter)->visual )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageDisconnection Setting visual(%d) off stage\n", (*iter)->index );
+      Actor self( Self() );
+      Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
+    }
   }
 }
 
@@ -872,10 +546,11 @@ void Control::OnChildRemove(Actor& child)
 
 void Control::OnSizeSet(const Vector3& targetSize)
 {
-  if( mImpl->mBackgroundVisual )
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
   {
     Vector2 size( targetSize );
-    mImpl->mBackgroundVisual.SetSize( size );
+    visual.SetSize( size );
   }
 }
 
@@ -910,6 +585,12 @@ void Control::OnRelayout( const Vector2& size, RelayoutContainer& container )
   {
     container.Add( Self().GetChildAt( i ), size );
   }
+
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
+  {
+    visual.SetSize( size );
+  }
 }
 
 void Control::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
@@ -918,11 +599,12 @@ void Control::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dime
 
 Vector3 Control::GetNaturalSize()
 {
-  if( mImpl->mBackgroundVisual )
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
   {
     Vector2 naturalSize;
-    mImpl->mBackgroundVisual.GetNaturalSize(naturalSize);
-    return Vector3(naturalSize);
+    visual.GetNaturalSize( naturalSize );
+    return Vector3( naturalSize );
   }
   return Vector3::ZERO;
 }
index edc088a..ff5a2e1 100644 (file)
@@ -675,7 +675,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;
 
 };