const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
const char* TEST_IMAGE_FILE_NAME2 = "gallery_image_02.jpg";
+const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
+const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
+
// resolution: 34*34, pixel format: RGBA8888
static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
// resolution: 600*600, pixel format: RGB888
END_TEST;
}
+
+
+int UtcDaliImageViewReplaceImage(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_IMAGE_1 );
+
+ 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);
+
+ // loading started, this waits for the loader thread for max 30 seconds
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( imageView.GetRendererCount(), 1u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+ gResourceReadySignalFired = false;
+
+ imageView.SetImage(TEST_IMAGE_2);
+
+ application.SendNotification();
+ application.Render(16);
+
+ // loading started, this waits for the loader thread for max 30 seconds
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( imageView.GetRendererCount(), 1u, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( Toolkit::DevelControl::IsResourceReady( imageView ), true, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+ END_TEST;
+}
bool IsResourceReady( const Control& control )
{
const Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
- const Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl );
+ const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
- return controlImpl.IsResourceReady();
+ return controlDataImpl.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 );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.RegisterVisual( index, visual );
}
void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
{
- Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- controlImpl.RegisterVisual( index, visual, depthIndex );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.RegisterVisual( index, visual, depthIndex );
}
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 );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.RegisterVisual( index, visual, enabled );
}
void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
{
- Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- controlImpl.RegisterVisual( index, visual, enabled, depthIndex );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.RegisterVisual( index, visual, enabled, depthIndex );
}
void UnregisterVisual( Internal::Control& control, Dali::Property::Index index )
{
- Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- controlImpl.UnregisterVisual( index );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.UnregisterVisual( index );
}
Toolkit::Visual::Base GetVisual( const Internal::Control& control, Dali::Property::Index index )
{
- const Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- return controlImpl.GetVisual( index );
+ const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ return controlDataImpl.GetVisual( index );
}
void EnableVisual( Internal::Control& control, Dali::Property::Index index, bool enable )
{
- Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- controlImpl.EnableVisual( index, enable );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ controlDataImpl.EnableVisual( index, enable );
}
bool IsVisualEnabled( const Internal::Control& control, Dali::Property::Index index )
{
- const Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- return controlImpl.IsVisualEnabled( index );
+ const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ return controlDataImpl.IsVisualEnabled( index );
}
Dali::Animation CreateTransition( Internal::Control& control, const Toolkit::TransitionData& handle )
{
- Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( control );
- return controlImpl.CreateTransition( handle );
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+ return controlDataImpl.CreateTransition( handle );
}
return visualHandle;
}
+/**
+ * Move visual from source to destination container
+ */
+void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination )
+{
+ Toolkit::Visual::Base visual = (*sourceIter)->visual;
+ if( visual )
+ {
+ RegisteredVisual* rv = source.Release( sourceIter );
+ destination.PushBack( rv );
+ }
+}
+
/**
* Performs actions as requested using the action name.
* @param[in] object The object on which to perform the action.
// Called by a Visual when it's resource is ready
void Control::Impl::ResourceReady( Visual::Base& object)
{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceReady \n");
+
+ // A resource is ready, check if is in the replacement visual container
+ // Iterate through all visuals in replacement container and store indexes of ready visuals
+ Dali::Vector <Property::Index> readyVisuals;
+ Actor self = mControlImpl.Self();
+
+ for( auto replacementVisualIter = mReplacementVisuals.Begin();
+ replacementVisualIter < mReplacementVisuals.End(); ++replacementVisualIter )
+ {
+ const Toolkit::Visual::Base replacementVisual = (*replacementVisualIter)->visual;
+ const Internal::Visual::Base& replacementVisualImpl = Toolkit::GetImplementation( replacementVisual );
+
+ if( replacementVisualImpl.IsResourceReady() )
+ {
+ // Check if new replacement visual (index) is already queued for replacement and swap old for new.
+ RegisteredVisualContainer::Iterator registeredVisualsIter;
+ if( FindVisual( (*replacementVisualIter)->index, mVisuals, registeredVisualsIter ) )
+ {
+ Property::Index readyVisualIndex = (*replacementVisualIter)->index;
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceReady: %d Ready to replace\n", readyVisualIndex );
+ readyVisuals.PushBack( readyVisualIndex );
+ // Remove current shown visual from stage and from registered visuals container
+ Toolkit::GetImplementation((*registeredVisualsIter)->visual).SetOffStage( self );
+ mVisuals.Erase( registeredVisualsIter );
+ }
+ }
+ }
+
+ for( auto readyVisualsIter = readyVisuals.Begin(); readyVisualsIter != readyVisuals.End(); readyVisualsIter++ )
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceReady: %d Matched\n", (*readyVisualsIter) );
+ // Move new visual to be shown from replacement container into the control's registered visuals container
+ // Replacement visual has already been set on stage when it was added to replacement container
+ RegisteredVisualContainer::Iterator readyReplacementVisual;
+ if( FindVisual( (*readyVisualsIter) , mReplacementVisuals, readyReplacementVisual ) )
+ {
+ MoveVisual( readyReplacementVisual, mReplacementVisuals, mVisuals ); // Erases visual from replacement queue
+ }
+ // A visual has been replaced so control will most likely need relayouting
+ mControlImpl.RelayoutRequest();
+ }
// go through and check if all the visuals are ready, if they are emit a signal
- for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
+ for( auto visualIter = mVisuals.Begin();
visualIter != mVisuals.End(); ++visualIter )
{
const Toolkit::Visual::Base visual = (*visualIter)->visual;
// all the visuals are ready
Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
mResourceReadySignal.Emit( handle );
-
}
bool Control::Impl::IsResourceReady() const
void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex )
{
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index );
+
bool visualReplaced ( false );
Actor self = mControlImpl.Self();
if( !mVisuals.Empty() )
{
- RegisteredVisualContainer::Iterator iter;
+ RegisteredVisualContainer::Iterator registeredVisualsiter;
// Check if visual (index) is already registered. Replace if so.
- if ( FindVisual( index, mVisuals, iter ) )
+ if( FindVisual( index, mVisuals, registeredVisualsiter ) )
{
- if( (*iter)->visual && self.OnStage() )
+ if( (*registeredVisualsiter)->visual )
{
- Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
- }
+ // Store current visual depth index as may need to set the replacement visual to same depth
+ const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
- // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
- if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
- ( visual.GetDepthIndex() == 0 ) )
- {
- const int currentDepthIndex = (*iter)->visual.GetDepthIndex();
- visual.SetDepthIndex( currentDepthIndex );
- }
+ // Monitor when the visuals resources are ready
+ StopObservingVisual( (*registeredVisualsiter)->visual );
+ StartObservingVisual( visual );
+
+ if( self.OnStage() )
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RegisterVisual Adding visual to replacement Queue: %d \n", index );
+ // Check if visual is currently in the process of being replaced
+ RegisteredVisualContainer::Iterator queuedReplacementVisual;
+ if ( FindVisual( index, mReplacementVisuals, queuedReplacementVisual ) )
+ {
+ // If visual on replacement queue is going to be replaced before it's ready then will be removed from queue (and stage)
+ // Only the the last requested visual will be queued and then displayed.
+ Toolkit::GetImplementation( (*queuedReplacementVisual)->visual ).SetOffStage( self );
+ mReplacementVisuals.Erase(queuedReplacementVisual);
+ }
+ // Add to replacement list
+ mReplacementVisuals.PushBack( new RegisteredVisual( index, visual, ( enabled == VisualState::ENABLED ? true : false ) ) );
+ }
+ else
+ {
+ // Not staged so can just replace registered visual
+ (*registeredVisualsiter)->visual = visual;
+ (*registeredVisualsiter)->enabled = ( enabled == VisualState::ENABLED ) ? true : false;
+ }
- StopObservingVisual( (*iter)->visual );
- StartObservingVisual( visual );
+ // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
+ if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
+ ( visual.GetDepthIndex() == 0 ) )
+ {
+ visual.SetDepthIndex( currentDepthIndex );
+ }
+ }
- (*iter)->visual = visual;
- (*iter)->enabled = ( enabled == VisualState::ENABLED ) ? true : false;
visualReplaced = true;
}
}
if( !visualReplaced ) // New registration entry
{
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "New Visual registration %d\n", index);
mVisuals.PushBack( new RegisteredVisual( index, visual, ( enabled == VisualState::ENABLED ? true : false ) ) );
// monitor when the visuals resources are ready
// Put on stage if enabled and the control is already on the stage
if( ( enabled == VisualState::ENABLED ) && self.OnStage() )
{
+ // Visual must be set on stage for the renderer to be created and the ResourceReady triggered.
Toolkit::GetImplementation(visual).SetOnStage( self );
}
}
void Control::Impl::EnableVisual( Property::Index index, bool enable )
{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual (%d)\n", index);
+
RegisteredVisualContainer::Iterator iter;
if ( FindVisual( index, mVisuals, iter ) )
{
/**
* @brief Adds the visual to the list of registered visuals.
* @param[in] index The Property index of the visual, used to reference visual
- * @param[in] visual The visual to register
+ * @param[in,out] visual The visual to register, which can be altered in this function
* @param[in] enabled false if derived class wants to control when visual is set on stage
* @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
* @param[in] depthIndex The visual's depth-index is set to this
+ *
+ * @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
+ * occur once the replacement visual is ready (loaded).
*/
void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = 0 );
bool mIsKeyboardNavigationSupported :1; ///< Stores whether keyboard navigation is supported by the control.
bool mIsKeyboardFocusGroup :1; ///< Stores whether the control is a focus group.
+ RegisteredVisualContainer mReplacementVisuals; ///< List of visuals that will be used for replacing current visuals.
+
// 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;
/////////////////////////////////////////////////////////////
+void ImageView::OnInitialize()
+{
+ // ImageView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to ImageView
+ Dali::Toolkit::Control handle( GetOwner() );
+ Toolkit::DevelControl::ResourceReadySignal( handle ).Connect( this, &ImageView::OnResourceReady );
+}
+
void ImageView::SetImage( Image image )
{
// Don't bother comparing if we had a visual previously, just drop old visual and create new one
mUrl.clear();
mPropertyMap.Clear();
- mVisual = Toolkit::VisualFactory::Get().CreateVisual( image );
- DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual );
+ Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( image );
+ if (!mVisual)
+ {
+ mVisual = visual;
+ }
- RelayoutRequest();
+ DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
}
void ImageView::SetImage( const Property::Map& map )
mPropertyMap = map;
mUrl.clear();
mImage.Reset();
+ Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( mPropertyMap );
+ // Don't set mVisual until it is ready and shown. Getters will still use current visual.
+ if (!mVisual)
+ {
+ mVisual = visual;
+ }
- mVisual = Toolkit::VisualFactory::Get().CreateVisual( mPropertyMap );
- DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual );
-
- RelayoutRequest();
+ DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
}
void ImageView::SetImage( const std::string& url, ImageDimensions size )
mImage.Reset();
mPropertyMap.Clear();
- mVisual = Toolkit::VisualFactory::Get().CreateVisual( url, size );
- DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, mVisual );
+ // Don't set mVisual until it is ready and shown. Getters will still use current visual.
+ Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, size );
+ if (!mVisual)
+ {
+ mVisual = visual;
+ }
- RelayoutRequest();
+ DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
}
Image ImageView::GetImage() const
}
}
+void ImageView::OnResourceReady( Toolkit::Control control )
+{
+ mVisual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+}
+
///////////////////////////////////////////////////////////
//
// Properties
private: // From Control
+ /**
+ * @copydoc Toolkit::Control::OnInitialize
+ */
+ void OnInitialize();
+
/**
* @copydoc Toolkit::Control::GetNaturalSize
*/
*/
virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+private:
+
+ /**
+ * @brief Callback for ResourceReadySignal
+ * param[in] control signal prototype
+ */
+ void OnResourceReady( Toolkit::Control control );
+
private:
// Undefined
ImageView( const ImageView& );
// Hold the weak handle of the placement actor and delay the adding of renderer until the svg rasterization is finished.
mPlacementActor = actor;
+
+ // SVG visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
+ ResourceReady();
}
void SvgVisual::DoSetOffStage( Actor& actor )
}
// Nothing else to do if the relayout size is zero.
+ ResourceReady();
return;
}