/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
#include <dali/public-api/object/type-registry.h>
// INTERNAL INCLUDES
+#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/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
{
const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
-constexpr float FULL_OPACITY = 1.0f;
-constexpr float LOW_OPACITY = 0.2f;
+constexpr float FULL_OPACITY = 1.0f;
+constexpr float LOW_OPACITY = 0.2f;
+constexpr float TRANSITION_EFFECT_SPEED = 0.3f;
+
+constexpr int PLACEHOLDER_DEPTH_INDEX = -2;
+constexpr int PREVIOUS_VISUAL_DEPTH_INDEX = -1;
+constexpr int CURRENT_VISUAL_DEPTH_INDEX = 0;
BaseHandle Create()
{
mTransitionTargetAlpha(FULL_OPACITY),
mImageVisualPaddingSetByTransform(false),
mImageViewPixelAreaSetByFittingMode(false),
- mTransitionEffect(false)
+ mTransitionEffect(false),
+ mNeedLazyFittingMode(false),
+ mImageReplaced(false)
{
}
{
if(mTransitionAnimation.GetState() == Animation::PLAYING)
{
- mTransitionAnimation.Stop();
+ // Hide placeholder
+ HidePlaceholderImage();
ClearTransitionAnimation();
}
}
mPropertyMap = map;
mUrl.clear();
+ mImageReplaced = true;
+
// keep alpha for transition effect
if(mTransitionEffect)
{
visualImpl.SetCustomShader(mShaderMap);
}
- DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+ DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
}
else
{
// Trigger a size negotiation request that may be needed when unregistering a visual.
RelayoutRequest();
}
-
// Signal that a Relayout may be needed
}
{
if(mTransitionAnimation.GetState() == Animation::PLAYING)
{
- mTransitionAnimation.Stop();
+ HidePlaceholderImage();
ClearTransitionAnimation();
}
}
mImageSize = size;
mPropertyMap.Clear();
+ mImageReplaced = true;
+
if(!mVisual)
{
ShowPlaceholderImage();
visualImpl.SetCustomShader(mShaderMap);
}
- DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+ DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
}
else
{
// Trigger a size negotiation request that may be needed when unregistering a visual.
RelayoutRequest();
}
-
// Signal that a Relayout may be needed
}
Control::OnRelayout(size, container);
if(mVisual)
{
- Property::Map transformMap = Property::Map();
-
- Extents padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
-
- bool zeroPadding = (padding == Extents());
-
- Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
- Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
- if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
+ // If Resource is not ready, fittingMode is not working well.
+ // in this case, imageview set the flag for working applyFittingMode again when the resource is ready
+ if(!IsResourceReady())
{
- std::swap(padding.start, padding.end);
+ mNeedLazyFittingMode = true;
}
- // remove padding from the size to know how much is left for the visual
- Vector2 finalSize = size - Vector2(padding.start + padding.end, padding.top + padding.bottom);
- Vector2 finalOffset = Vector2(padding.start, padding.top);
-
- ApplyFittingMode(finalSize, finalOffset, zeroPadding, transformMap);
-
- mVisual.SetTransformAndSize(transformMap, size);
+ // Apply FittingMode using actor's size
+ ApplyFittingMode(size);
// mVisual is not updated util the resource is ready in the case of visual replacement.
// in this case, the Property Map must be initialized so that the previous value is not reused.
{
visual.SetTransformAndSize(Property::Map(), size);
}
+
+ if(!mTransitionEffect)
+ {
+ // we don't need placeholder anymore because visual is replaced. so hide placeholder.
+ HidePlaceholderImage();
+ }
}
}
// when placeholder is disabled or ready placeholder and image, we need to transition effect
TransitionImageWithEffect();
}
- else
- {
- ClearTransitionAnimation();
- }
- }
- else
- {
- // we don't need placeholder anymore because visual is replaced. so hide placeholder.
- HidePlaceholderImage();
}
// Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
mVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
+
+ // Applying FittingMode again if it is not working well on OnRelayout().
+ if(mNeedLazyFittingMode)
+ {
+ const Vector2& size = Self().GetProperty(Dali::Actor::Property::SIZE).Get<Vector2>();
+ ApplyFittingMode(size);
+ mNeedLazyFittingMode = false;
+ }
+
// Signal that a Relayout may be needed
}
}
}
-void ImageView::ApplyFittingMode(Vector2 finalSize, Vector2 finalOffset, bool zeroPadding, Property::Map& transformMap)
+void ImageView::ApplyFittingMode(const Vector2& size)
{
+ Property::Map transformMap = Property::Map();
+
+ Extents padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
+
+ bool zeroPadding = (padding == Extents());
+
+ Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
+ Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
+ {
+ std::swap(padding.start, padding.end);
+ }
+
+ // remove padding from the size to know how much is left for the visual
+ Vector2 finalSize = size - Vector2(padding.start + padding.end, padding.top + padding.bottom);
+ Vector2 finalOffset = Vector2(padding.start, padding.top);
+
Visual::FittingMode fittingMode = Toolkit::GetImplementation(mVisual).GetFittingMode();
// Reset PIXEL_AREA after using OVER_FIT_KEEP_ASPECT_RATIO
.Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE));
}
+
+ mVisual.SetTransformAndSize(transformMap, size);
}
void ImageView::CreatePlaceholderImage()
propertyMap.Insert(Toolkit::ImageVisual::Property::URL, mPlaceholderUrl);
//propertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE); // TODO: need to enable this property
propertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED);
+ propertyMap.Insert(Toolkit::DevelImageVisual::Property::ENABLE_BROKEN_IMAGE, false);
mPlaceholderVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
if(mPlaceholderVisual)
{
mPlaceholderVisual.SetName("placeholder");
+ mPlaceholderVisual.SetDepthIndex(mPlaceholderVisual.GetDepthIndex() + PLACEHOLDER_DEPTH_INDEX);
}
else
{
if(handle)
{
- mTransitionAnimation = Animation::New(1.5f);
- mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
- float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
+ if(!mImageReplaced)
+ {
+ // If the image is not replaced, the transition effect is not required.
+ return;
+ }
- if(mPreviousVisual) // Transition previous image
+ if(mTransitionAnimation)
{
- Dali::KeyFrames fadeoutKeyFrames = Dali::KeyFrames::New();
- fadeoutKeyFrames.Add(0.0f, destinationAlpha);
- fadeoutKeyFrames.Add(1.0f, LOW_OPACITY);
- Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(mPreviousVisual);
- mTransitionAnimation.AnimateBetween(visualImpl.GetPropertyObject(Toolkit::Visual::Property::OPACITY), fadeoutKeyFrames);
+ ClearTransitionAnimation();
}
- else if(mPlaceholderVisual) // Transition placeholder
+
+ // Control visual's depth for transition effect
+ if(mPreviousVisual)
{
- Dali::KeyFrames fadeoutKeyFrames = Dali::KeyFrames::New();
- fadeoutKeyFrames.Add(0.0f, destinationAlpha);
- fadeoutKeyFrames.Add(1.0f, LOW_OPACITY);
- Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(mPlaceholderVisual);
- mTransitionAnimation.AnimateBetween(visualImpl.GetPropertyObject(Toolkit::Visual::Property::OPACITY), fadeoutKeyFrames);
+ mPreviousVisual.SetDepthIndex(mPreviousVisual.GetDepthIndex() + PREVIOUS_VISUAL_DEPTH_INDEX);
}
+ mTransitionAnimation = Animation::New(TRANSITION_EFFECT_SPEED);
+ mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
+ float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
+
// Transition current image
Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
if(imageVisual)
Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
fadeinKeyFrames.Add(1.0f, destinationAlpha);
- mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames);
+ mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames, AlphaFunction::EASE_IN_OUT);
+ imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX);
}
// Play transition animation
void ImageView::ClearTransitionAnimation()
{
- // Hide placeholder
- HidePlaceholderImage();
-
// Clear PreviousVisual
if(mPreviousVisual)
{
if(mTransitionAnimation)
{
+ if(mTransitionAnimation.GetState() == Animation::PLAYING)
+ {
+ mTransitionAnimation.Stop();
+ }
mTransitionAnimation.FinishedSignal().Disconnect(this, &ImageView::OnTransitionAnimationFinishedCallback);
mTransitionAnimation.Clear();
+ mTransitionAnimation.Reset();
+
+ // After transition effect is cleared, we don't need transition effect until image is replaced.
+ mImageReplaced = false;
}
}
void ImageView::OnTransitionAnimationFinishedCallback(Animation& animation)
{
+ // Hide placeholder
+ HidePlaceholderImage();
ClearTransitionAnimation();
}