X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fimage-view%2Fimage-view-impl.cpp;h=7f11261cf5b4c76d6eb4e966bb1fc9191568e0d2;hb=HEAD;hp=f893f46b82367254339f30bb88d32cc84fa3a7dc;hpb=08c00745e3c0f9930a48a5a07e6bf5441edafaab;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp index f893f46..91e33df 100644 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp @@ -1,5 +1,5 @@ /* - * 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. @@ -25,6 +25,7 @@ #include // INTERNAL INCLUDES +#include #include #include #include @@ -43,10 +44,13 @@ namespace Internal { namespace { -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 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() { @@ -59,6 +63,7 @@ DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "image", MAP, IMAGE) DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA) DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "placeholderImage", STRING, PLACEHOLDER_IMAGE) DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "enableTransitionEffect", BOOLEAN, ENABLE_TRANSITION_EFFECT) +DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "transitionEffectOption", MAP, TRANSITION_EFFECT_OPTION) DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA) DALI_TYPE_REGISTRATION_END() @@ -70,10 +75,8 @@ ImageView::ImageView(ControlBehaviour additionalBehaviour) : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour)), mImageSize(), mTransitionTargetAlpha(FULL_OPACITY), - mImageVisualPaddingSetByTransform(false), - mImageViewPixelAreaSetByFittingMode(false), mTransitionEffect(false), - mNeedLazyFittingMode(false) + mImageReplaced(false) { } @@ -116,7 +119,8 @@ void ImageView::SetImage(const Property::Map& map) { if(mTransitionAnimation.GetState() == Animation::PLAYING) { - mTransitionAnimation.Stop(); + // Hide placeholder + HidePlaceholderImage(); ClearTransitionAnimation(); } } @@ -133,6 +137,8 @@ void ImageView::SetImage(const Property::Map& map) mPropertyMap = map; mUrl.clear(); + mImageReplaced = true; + // keep alpha for transition effect if(mTransitionEffect) { @@ -152,6 +158,12 @@ void ImageView::SetImage(const Property::Map& map) Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(mPropertyMap); if(visual) { + Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); + if(visualImpl.GetFittingMode() == Visual::FittingMode::DONT_CARE) + { + visualImpl.SetFittingMode(Visual::FittingMode::FILL); + } + // Don't set mVisual until it is ready and shown. Getters will still use current visual. if(!mVisual) { @@ -160,11 +172,10 @@ void ImageView::SetImage(const Property::Map& map) if(!mShaderMap.Empty()) { - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); visualImpl.SetCustomShader(mShaderMap); } - DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual); + DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT); } else { @@ -174,7 +185,6 @@ void ImageView::SetImage(const Property::Map& map) // Trigger a size negotiation request that may be needed when unregistering a visual. RelayoutRequest(); } - // Signal that a Relayout may be needed } @@ -189,7 +199,7 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size) { if(mTransitionAnimation.GetState() == Animation::PLAYING) { - mTransitionAnimation.Stop(); + HidePlaceholderImage(); ClearTransitionAnimation(); } } @@ -207,6 +217,8 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size) mImageSize = size; mPropertyMap.Clear(); + mImageReplaced = true; + if(!mVisual) { ShowPlaceholderImage(); @@ -216,6 +228,12 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size) Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, size); if(visual) { + Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); + if(visualImpl.GetFittingMode() == Visual::FittingMode::DONT_CARE) + { + visualImpl.SetFittingMode(Visual::FittingMode::FILL); + } + if(!mVisual) { mVisual = visual; @@ -223,11 +241,10 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size) if(!mShaderMap.Empty()) { - Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); visualImpl.SetCustomShader(mShaderMap); } - DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual); + DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT); } else { @@ -237,7 +254,6 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size) // Trigger a size negotiation request that may be needed when unregistering a visual. RelayoutRequest(); } - // Signal that a Relayout may be needed } @@ -317,6 +333,11 @@ bool ImageView::IsTransitionEffectEnabled() const return mTransitionEffect; } +void ImageView::SetTransitionEffectOption(const Property::Map& map) +{ + mTransitionEffectOptionMap = map; +} + Vector3 ImageView::GetNaturalSize() { if(mVisual) @@ -371,16 +392,6 @@ void ImageView::OnRelayout(const Vector2& size, RelayoutContainer& container) Control::OnRelayout(size, container); if(mVisual) { - // 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()) - { - mNeedLazyFittingMode = true; - } - - // 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. // after mVisual is updated, the correct value will be reset. @@ -389,6 +400,12 @@ void ImageView::OnRelayout(const Vector2& size, RelayoutContainer& container) { visual.SetTransformAndSize(Property::Map(), size); } + + if(!mTransitionEffect) + { + // we don't need placeholder anymore because visual is replaced. so hide placeholder. + HidePlaceholderImage(); + } } } @@ -444,184 +461,14 @@ void ImageView::OnResourceReady(Toolkit::Control control) // 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(); - ApplyFittingMode(size); - mNeedLazyFittingMode = false; - } - // Signal that a Relayout may be needed } -void ImageView::SetTransformMapForFittingMode(Vector2 finalSize, Vector2 naturalSize, Vector2 finalOffset, Visual::FittingMode fittingMode, Property::Map& transformMap) -{ - switch(fittingMode) - { - case Visual::FittingMode::FIT_KEEP_ASPECT_RATIO: - { - auto availableVisualSize = finalSize; - - // scale to fit the padded area - finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0), - (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0)); - - // calculate final offset within the padded area - finalOffset += (availableVisualSize - finalSize) * .5f; - - // populate the transform map - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset) - .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize); - break; - } - case Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO: - { - mImageViewPixelAreaSetByFittingMode = true; - auto availableVisualSize = finalSize; - finalSize = naturalSize * std::max((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f), - (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f)); - - auto originalOffset = finalOffset; - finalOffset += (availableVisualSize - finalSize) * .5f; - - float x = abs((availableVisualSize.width - finalSize.width) / finalSize.width) * .5f; - float y = abs((availableVisualSize.height - finalSize.height) / finalSize.height) * .5f; - float widthRatio = 1.f - abs((availableVisualSize.width - finalSize.width) / finalSize.width); - float heightRatio = 1.f - abs((availableVisualSize.height - finalSize.height) / finalSize.height); - Vector4 pixelArea = Vector4(x, y, widthRatio, heightRatio); - Self().SetProperty(Toolkit::ImageView::Property::PIXEL_AREA, pixelArea); - - // populate the transform map - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, originalOffset) - .Add(Toolkit::Visual::Transform::Property::SIZE, availableVisualSize); - break; - } - case Visual::FittingMode::CENTER: - { - auto availableVisualSize = finalSize; - if(availableVisualSize.width > naturalSize.width && availableVisualSize.height > naturalSize.height) - { - finalSize = naturalSize; - } - else - { - finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f), - (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f)); - } - - finalOffset += (availableVisualSize - finalSize) * .5f; - - // populate the transform map - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset) - .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize); - break; - } - case Visual::FittingMode::FILL: - { - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset) - .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize); - break; - } - case Visual::FittingMode::FIT_WIDTH: - case Visual::FittingMode::FIT_HEIGHT: - { - // This FittingMode already converted - break; - } - } -} - -void ImageView::ApplyFittingMode(const Vector2& size) -{ - Property::Map transformMap = Property::Map(); - - Extents padding = Self().GetProperty(Toolkit::Control::Property::PADDING); - - bool zeroPadding = (padding == Extents()); - - Dali::LayoutDirection::Type layoutDirection = static_cast( - Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get()); - 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 - if(mImageViewPixelAreaSetByFittingMode) - { - Self().SetProperty(Toolkit::ImageView::Property::PIXEL_AREA, FULL_TEXTURE_RECT); - mImageViewPixelAreaSetByFittingMode = false; - } - - if((!zeroPadding) || // If padding is not zero - (fittingMode != Visual::FittingMode::FILL)) - { - mImageVisualPaddingSetByTransform = true; - - Vector2 naturalSize; - // NaturalSize will not be used for FILL fitting mode, which is default. - // Skip GetNaturalSize - if(fittingMode != Visual::FittingMode::FILL) - { - mVisual.GetNaturalSize(naturalSize); - } - - // If FittingMode use FIT_WIDTH or FIT_HEIGTH, it need to change proper fittingMode - if(fittingMode == Visual::FittingMode::FIT_WIDTH) - { - fittingMode = (finalSize.height / naturalSize.height) < (finalSize.width / naturalSize.width) ? Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::FIT_KEEP_ASPECT_RATIO; - } - else if(fittingMode == Visual::FittingMode::FIT_HEIGHT) - { - fittingMode = (finalSize.height / naturalSize.height) < (finalSize.width / naturalSize.width) ? Visual::FittingMode::FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO; - } - - SetTransformMapForFittingMode(finalSize, naturalSize, finalOffset, fittingMode, transformMap); - - // Set extra value for applying transformMap - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, - Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) - .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) - .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN) - .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, - Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)); - } - else if(mImageVisualPaddingSetByTransform && zeroPadding) // Reset offset to zero only if padding applied previously - { - mImageVisualPaddingSetByTransform = false; - // Reset the transform map - transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO) - .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, - Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE)) - .Add(Toolkit::Visual::Transform::Property::SIZE, Vector2::ONE) - .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() { Property::Map propertyMap; @@ -634,6 +481,7 @@ void ImageView::CreatePlaceholderImage() if(mPlaceholderVisual) { mPlaceholderVisual.SetName("placeholder"); + mPlaceholderVisual.SetDepthIndex(mPlaceholderVisual.GetDepthIndex() + PLACEHOLDER_DEPTH_INDEX); } else { @@ -670,48 +518,72 @@ void ImageView::TransitionImageWithEffect() 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); } // 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); - } + imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX); + if(!mTransitionEffectOptionMap.Empty()) + { + // Set user's transition effect options + Dali::Toolkit::TransitionData transition = Toolkit::TransitionData::New(mTransitionEffectOptionMap); + Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this); + mTransitionAnimation = controlDataImpl.CreateTransition(transition); + if(mTransitionAnimation) + { + mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD); + mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback); + mTransitionAnimation.Play(); + } + else + { + DALI_LOG_ERROR("Create Transition Animation failed"); + } + } + else + { + 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, AlphaFunction::EASE_IN_OUT); + imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX); + } - // Play transition animation - mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback); - mTransitionAnimation.Play(); + // Play transition animation + mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback); + mTransitionAnimation.Play(); + } + } } } void ImageView::ClearTransitionAnimation() { - // Hide placeholder - HidePlaceholderImage(); - // Clear PreviousVisual if(mPreviousVisual) { @@ -724,8 +596,16 @@ void ImageView::ClearTransitionAnimation() 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; } } @@ -828,6 +708,14 @@ void ImageView::SetProperty(BaseObject* object, Property::Index index, const Pro } break; } + case Toolkit::ImageView::Property::TRANSITION_EFFECT_OPTION: + { + Property::Map map; + if(value.Get(map)) + { + impl.SetTransitionEffectOption(map); + } + } } } } @@ -887,6 +775,8 @@ Property::Value ImageView::GetProperty(BaseObject* object, Property::Index prope void ImageView::OnTransitionAnimationFinishedCallback(Animation& animation) { + // Hide placeholder + HidePlaceholderImage(); ClearTransitionAnimation(); }