Apply placeholder image & transition effect
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / image-view / image-view-impl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "image-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/scripting/scripting.h>
23 #include <dali/public-api/math/math-utils.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/object/type-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/controls/control-devel.h>
29 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
30 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
31 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
32 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
33 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
36 #include <dali-toolkit/public-api/visuals/visual-properties.h>
37
38 namespace Dali
39 {
40 namespace Toolkit
41 {
42 namespace Internal
43 {
44 namespace
45 {
46 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
47
48 constexpr float FULL_OPACITY = 1.0f;
49 constexpr float LOW_OPACITY  = 0.2f;
50
51 BaseHandle Create()
52 {
53   return Toolkit::ImageView::New();
54 }
55
56 // Setup properties, signals and actions using the type-registry.
57 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::ImageView, Toolkit::Control, Create);
58 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "image", MAP, IMAGE)
59 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA)
60 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "placeholderImage", STRING, PLACEHOLDER_IMAGE)
61 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "enableTransitionEffect", BOOLEAN, ENABLE_TRANSITION_EFFECT)
62 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA)
63 DALI_TYPE_REGISTRATION_END()
64
65 } // anonymous namespace
66
67 using namespace Dali;
68
69 ImageView::ImageView(ControlBehaviour additionalBehaviour)
70 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour)),
71   mImageSize(),
72   mTransitionTargetAlpha(FULL_OPACITY),
73   mImageVisualPaddingSetByTransform(false),
74   mImageViewPixelAreaSetByFittingMode(false),
75   mTransitionEffect(false)
76 {
77 }
78
79 ImageView::~ImageView()
80 {
81 }
82
83 Toolkit::ImageView ImageView::New(ControlBehaviour additionalBehaviour)
84 {
85   ImageView* impl = new ImageView(additionalBehaviour);
86
87   Toolkit::ImageView handle = Toolkit::ImageView(*impl);
88
89   // Second-phase init of the implementation
90   // This can only be done after the CustomActor connection has been made...
91   impl->Initialize();
92
93   return handle;
94 }
95
96 /////////////////////////////////////////////////////////////
97
98 void ImageView::OnInitialize()
99 {
100   // ImageView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to ImageView
101   Dali::Toolkit::Control handle(GetOwner());
102   handle.ResourceReadySignal().Connect(this, &ImageView::OnResourceReady);
103
104   Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::IMAGE);
105 }
106
107 void ImageView::SetImage(const Property::Map& map)
108 {
109   DALI_LOG_ERROR("tscholb : SetImage(map) !!! \n");
110   if(mTransitionEffect && mVisual)
111   {
112     // Clear previous transition effect if it is playing
113     if(mPreviousVisual)
114     {
115       if(mTransitionAnimation)
116       {
117         if(mTransitionAnimation.GetState() == Animation::PLAYING)
118         {
119           mTransitionAnimation.Stop();
120           ClearTransitionAnimation();
121         }
122       }
123     }
124
125     // Enable transition effect for previous visual.
126     // This previous visual will be deleted when transition effect is done.
127     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
128     controlDataImpl.EnableReadyTransitionOverriden(mVisual, true);
129     mPreviousVisual = mVisual;
130   }
131
132   // Comparing a property map is too expensive so just creating a new visual
133   mPropertyMap = map;
134   mUrl.clear();
135
136   // keep alpha for transition effect
137   if(mTransitionEffect)
138   {
139     float            alpha      = FULL_OPACITY;
140     Property::Value* alphaValue = map.Find(Toolkit::Visual::Property::OPACITY);
141     if(alphaValue && alphaValue->Get(alpha))
142     {
143       mTransitionTargetAlpha = alpha;
144     }
145   }
146
147   if(!mVisual)
148   {
149     ShowPlaceholderImage();
150   }
151
152   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(mPropertyMap);
153   if(visual)
154   {
155     // Don't set mVisual until it is ready and shown. Getters will still use current visual.
156     if(!mVisual)
157     {
158       mVisual = visual;
159     }
160
161     if(!mShaderMap.Empty())
162     {
163       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
164       visualImpl.SetCustomShader(mShaderMap);
165     }
166
167     DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
168   }
169   else
170   {
171     // Unregister the exsiting visual
172     DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::IMAGE);
173
174     // Trigger a size negotiation request that may be needed when unregistering a visual.
175     RelayoutRequest();
176   }
177
178   // Signal that a Relayout may be needed
179 }
180
181 void ImageView::SetImage(const std::string& url, ImageDimensions size)
182 {
183   DALI_LOG_ERROR("tscholb : SetImage !!! \n");
184   if(mTransitionEffect && mVisual)
185   {
186     // Clear previous transition effect if it is playing
187     if(mPreviousVisual)
188     {
189       if(mTransitionAnimation)
190       {
191         if(mTransitionAnimation.GetState() == Animation::PLAYING)
192         {
193           mTransitionAnimation.Stop();
194           ClearTransitionAnimation();
195         }
196       }
197     }
198
199     // Enable transition effect for previous visual.
200     // This previous visual will be deleted when transition effect is done.
201     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
202     controlDataImpl.EnableReadyTransitionOverriden(mVisual, true);
203     mPreviousVisual = mVisual;
204   }
205
206   // Don't bother comparing if we had a visual previously, just drop old visual and create new one
207   mUrl       = url;
208   mImageSize = size;
209   mPropertyMap.Clear();
210
211   if(!mVisual)
212   {
213     ShowPlaceholderImage();
214   }
215
216   // Don't set mVisual until it is ready and shown. Getters will still use current visual.
217   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, size);
218   if(visual)
219   {
220     if(!mVisual)
221     {
222       mVisual = visual;
223     }
224
225     if(!mShaderMap.Empty())
226     {
227       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
228       visualImpl.SetCustomShader(mShaderMap);
229     }
230
231     DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
232   }
233   else
234   {
235     // Unregister the exsiting visual
236     DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::IMAGE);
237
238     // Trigger a size negotiation request that may be needed when unregistering a visual.
239     RelayoutRequest();
240   }
241
242   //tscholb DEBUG
243   Dali::Toolkit::Control handle(GetOwner());
244   auto                   check1 = handle.GetVisualResourceStatus(Toolkit::ImageView::Property::IMAGE);
245   auto                   check2 = handle.GetVisualResourceStatus(Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
246   DALI_LOG_ERROR("tscholb : Resource status check >> %d,%d \n", check1, check2);
247
248   // Signal that a Relayout may be needed
249 }
250
251 void ImageView::ClearImageVisual()
252 {
253   // Clear cached properties
254   mPropertyMap.Clear();
255   mUrl.clear();
256   mVisual.Reset();
257
258   // Unregister the exsiting visual
259   DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::IMAGE);
260
261   // Trigger a size negotiation request that may be needed when unregistering a visual.
262   RelayoutRequest();
263 }
264
265 void ImageView::EnablePreMultipliedAlpha(bool preMultipled)
266 {
267   if(mVisual)
268   {
269     Toolkit::GetImplementation(mVisual).EnablePreMultipliedAlpha(preMultipled);
270   }
271 }
272
273 bool ImageView::IsPreMultipliedAlphaEnabled() const
274 {
275   if(mVisual)
276   {
277     return Toolkit::GetImplementation(mVisual).IsPreMultipliedAlphaEnabled();
278   }
279   return false;
280 }
281
282 void ImageView::SetDepthIndex(int depthIndex)
283 {
284   if(mVisual)
285   {
286     mVisual.SetDepthIndex(depthIndex);
287   }
288 }
289
290 void ImageView::SetPlaceholderUrl(const std::string& url)
291 {
292   mPlaceholderUrl = url;
293   if(!url.empty())
294   {
295     mPlaceholderVisual.Reset();
296     CreatePlaceholderImage();
297   }
298   else
299   {
300     // Clear current placeholder image
301     Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
302     if(visual)
303     {
304       DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
305     }
306
307     mPlaceholderVisual.Reset();
308     mPlaceholderUrl = url;
309   }
310 }
311
312 std::string ImageView::GetPlaceholderUrl() const
313 {
314   return mPlaceholderUrl;
315 }
316
317 void ImageView::EnableTransitionEffect(bool effectEnable)
318 {
319   mTransitionEffect = effectEnable;
320 }
321
322 bool ImageView::IsTransitionEffectEnabled() const
323 {
324   return mTransitionEffect;
325 }
326
327 Vector3 ImageView::GetNaturalSize()
328 {
329   if(mVisual)
330   {
331     Vector2 rendererNaturalSize;
332     mVisual.GetNaturalSize(rendererNaturalSize);
333
334     Extents padding;
335     padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
336
337     rendererNaturalSize.width += (padding.start + padding.end);
338     rendererNaturalSize.height += (padding.top + padding.bottom);
339     return Vector3(rendererNaturalSize);
340   }
341
342   // if no visual then use Control's natural size
343   return Control::GetNaturalSize();
344 }
345
346 float ImageView::GetHeightForWidth(float width)
347 {
348   Extents padding;
349   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
350
351   if(mVisual)
352   {
353     return mVisual.GetHeightForWidth(width) + padding.top + padding.bottom;
354   }
355   else
356   {
357     return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
358   }
359 }
360
361 float ImageView::GetWidthForHeight(float height)
362 {
363   Extents padding;
364   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
365
366   if(mVisual)
367   {
368     return mVisual.GetWidthForHeight(height) + padding.start + padding.end;
369   }
370   else
371   {
372     return Control::GetWidthForHeight(height) + padding.start + padding.end;
373   }
374 }
375
376 void ImageView::OnRelayout(const Vector2& size, RelayoutContainer& container)
377 {
378   Control::OnRelayout(size, container);
379   if(mVisual)
380   {
381     Property::Map transformMap = Property::Map();
382
383     Extents padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
384
385     bool zeroPadding = (padding == Extents());
386
387     Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
388       Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
389     if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
390     {
391       std::swap(padding.start, padding.end);
392     }
393
394     // remove padding from the size to know how much is left for the visual
395     Vector2 finalSize   = size - Vector2(padding.start + padding.end, padding.top + padding.bottom);
396     Vector2 finalOffset = Vector2(padding.start, padding.top);
397
398     ApplyFittingMode(finalSize, finalOffset, zeroPadding, transformMap);
399
400     mVisual.SetTransformAndSize(transformMap, size);
401
402     // mVisual is not updated util the resource is ready in the case of visual replacement.
403     // in this case, the Property Map must be initialized so that the previous value is not reused.
404     // after mVisual is updated, the correct value will be reset.
405     Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
406     if(visual && visual != mVisual)
407     {
408       visual.SetTransformAndSize(Property::Map(), size);
409     }
410   }
411 }
412
413 void ImageView::OnCreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
414                                     std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
415                                     Dali::Toolkit::Control                                              source,
416                                     Dali::Toolkit::Control                                              destination)
417 {
418   // Retrieves image properties to be transitioned.
419   Dali::Property::Map imageSourcePropertyMap, imageDestinationPropertyMap;
420   MakeVisualTransition(imageSourcePropertyMap, imageDestinationPropertyMap, source, destination, Toolkit::ImageView::Property::IMAGE);
421   if(imageSourcePropertyMap.Count() > 0)
422   {
423     sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE, imageSourcePropertyMap));
424     destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE, imageDestinationPropertyMap));
425   }
426 }
427
428 void ImageView::OnUpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
429 {
430   Toolkit::Visual::Base visual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
431   if(visual)
432   {
433     Dali::Toolkit::Control handle(GetOwner());
434
435     for(auto&& data : properties)
436     {
437       if(data.first == Toolkit::ImageView::Property::IMAGE)
438       {
439         DevelControl::DoAction(handle, Toolkit::ImageView::Property::IMAGE, DevelVisual::Action::UPDATE_PROPERTY, data.second);
440         break;
441       }
442     }
443   }
444 }
445
446 void ImageView::OnResourceReady(Toolkit::Control control)
447 {
448   DALI_LOG_ERROR("tscholb : OnResourceReady !!! \n");
449   // In case of placeholder, we need to skip this call.
450   // TODO: In case of placeholder, it needs to be modified not to call OnResourceReady()
451   if(control.GetVisualResourceStatus(Toolkit::ImageView::Property::IMAGE) != Toolkit::Visual::ResourceStatus::READY)
452   {
453     DALI_LOG_ERROR("tscholb : OnResourceReady() is called, but SKIP \n");
454     return;
455   }
456
457   // Do transition effect if need.
458   if(mTransitionEffect)
459   {
460     // TODO: Consider about placeholder image is loaded failed
461     Toolkit::Visual::Base placeholderVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
462     if(!placeholderVisual || control.GetVisualResourceStatus(Toolkit::ImageView::Property::PLACEHOLDER_IMAGE) == Toolkit::Visual::ResourceStatus::READY)
463     {
464       // when placeholder is disabled or ready placeholder and image, we need to transition effect
465       DALI_LOG_ERROR("tscholb : Call TransitionEffect \n");
466       TransitionImageWithEffect();
467     }
468     else
469     {
470       DALI_LOG_ERROR("tscholb : Call ClearTransitionAnimation \n");
471       ClearTransitionAnimation();
472     }
473   }
474   else
475   {
476     // we don't need placeholder anymore because visual is replaced. so hide placeholder.
477     DALI_LOG_ERROR("tscholb : transition effect is DISABLE \n");
478     HidePlaceholderImage();
479   }
480
481   // Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
482   mVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
483   // Signal that a Relayout may be needed
484 }
485
486 void ImageView::SetTransformMapForFittingMode(Vector2 finalSize, Vector2 naturalSize, Vector2 finalOffset, Visual::FittingMode fittingMode, Property::Map& transformMap)
487 {
488   switch(fittingMode)
489   {
490     case Visual::FittingMode::FIT_KEEP_ASPECT_RATIO:
491     {
492       auto availableVisualSize = finalSize;
493
494       // scale to fit the padded area
495       finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0),
496                                          (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0));
497
498       // calculate final offset within the padded area
499       finalOffset += (availableVisualSize - finalSize) * .5f;
500
501       // populate the transform map
502       transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
503         .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
504       break;
505     }
506     case Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO:
507     {
508       mImageViewPixelAreaSetByFittingMode = true;
509       auto availableVisualSize            = finalSize;
510       finalSize                           = naturalSize * std::max((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
511                                          (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
512
513       auto originalOffset = finalOffset;
514       finalOffset += (availableVisualSize - finalSize) * .5f;
515
516       float   x           = abs((availableVisualSize.width - finalSize.width) / finalSize.width) * .5f;
517       float   y           = abs((availableVisualSize.height - finalSize.height) / finalSize.height) * .5f;
518       float   widthRatio  = 1.f - abs((availableVisualSize.width - finalSize.width) / finalSize.width);
519       float   heightRatio = 1.f - abs((availableVisualSize.height - finalSize.height) / finalSize.height);
520       Vector4 pixelArea   = Vector4(x, y, widthRatio, heightRatio);
521       Self().SetProperty(Toolkit::ImageView::Property::PIXEL_AREA, pixelArea);
522
523       // populate the transform map
524       transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, originalOffset)
525         .Add(Toolkit::Visual::Transform::Property::SIZE, availableVisualSize);
526       break;
527     }
528     case Visual::FittingMode::CENTER:
529     {
530       auto availableVisualSize = finalSize;
531       if(availableVisualSize.width > naturalSize.width && availableVisualSize.height > naturalSize.height)
532       {
533         finalSize = naturalSize;
534       }
535       else
536       {
537         finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
538                                            (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
539       }
540
541       finalOffset += (availableVisualSize - finalSize) * .5f;
542
543       // populate the transform map
544       transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
545         .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
546       break;
547     }
548     case Visual::FittingMode::FILL:
549     {
550       transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
551         .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
552       break;
553     }
554     case Visual::FittingMode::FIT_WIDTH:
555     case Visual::FittingMode::FIT_HEIGHT:
556     {
557       // This FittingMode already converted
558       break;
559     }
560   }
561 }
562
563 void ImageView::ApplyFittingMode(Vector2 finalSize, Vector2 finalOffset, bool zeroPadding, Property::Map& transformMap)
564 {
565   Visual::FittingMode fittingMode = Toolkit::GetImplementation(mVisual).GetFittingMode();
566
567   // Reset PIXEL_AREA after using OVER_FIT_KEEP_ASPECT_RATIO
568   if(mImageViewPixelAreaSetByFittingMode)
569   {
570     Self().SetProperty(Toolkit::ImageView::Property::PIXEL_AREA, FULL_TEXTURE_RECT);
571     mImageViewPixelAreaSetByFittingMode = false;
572   }
573
574   if((!zeroPadding) || // If padding is not zero
575      (fittingMode != Visual::FittingMode::FILL))
576   {
577     mImageVisualPaddingSetByTransform = true;
578
579     Vector2 naturalSize;
580     // NaturalSize will not be used for FILL fitting mode, which is default.
581     // Skip GetNaturalSize
582     if(fittingMode != Visual::FittingMode::FILL)
583     {
584       mVisual.GetNaturalSize(naturalSize);
585     }
586
587     // If FittingMode use FIT_WIDTH or FIT_HEIGTH, it need to change proper fittingMode
588     if(fittingMode == Visual::FittingMode::FIT_WIDTH)
589     {
590       fittingMode = (finalSize.height / naturalSize.height) < (finalSize.width / naturalSize.width) ? Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::FIT_KEEP_ASPECT_RATIO;
591     }
592     else if(fittingMode == Visual::FittingMode::FIT_HEIGHT)
593     {
594       fittingMode = (finalSize.height / naturalSize.height) < (finalSize.width / naturalSize.width) ? Visual::FittingMode::FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO;
595     }
596
597     SetTransformMapForFittingMode(finalSize, naturalSize, finalOffset, fittingMode, transformMap);
598
599     // Set extra value for applying transformMap
600     transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
601                      Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
602       .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN)
603       .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN)
604       .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
605            Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE));
606   }
607   else if(mImageVisualPaddingSetByTransform && zeroPadding) // Reset offset to zero only if padding applied previously
608   {
609     mImageVisualPaddingSetByTransform = false;
610     // Reset the transform map
611     transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO)
612       .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
613            Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE))
614       .Add(Toolkit::Visual::Transform::Property::SIZE, Vector2::ONE)
615       .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
616            Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE));
617   }
618 }
619
620 void ImageView::CreatePlaceholderImage()
621 {
622   Property::Map propertyMap;
623   propertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
624   propertyMap.Insert(Toolkit::ImageVisual::Property::URL, mPlaceholderUrl);
625   //propertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE); // TODO: need to enable this property
626   propertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED);
627   mPlaceholderVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
628   if(mPlaceholderVisual)
629   {
630     mPlaceholderVisual.SetName("placeholder");
631   }
632   else
633   {
634     DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
635     mPlaceholderVisual.Reset();
636   }
637 }
638
639 void ImageView::ShowPlaceholderImage()
640 {
641   if(mPlaceholderVisual)
642   {
643     DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE, mPlaceholderVisual, false);
644     Actor self = Self();
645     Toolkit::GetImplementation(mPlaceholderVisual).SetOnScene(self);
646   }
647 }
648
649 void ImageView::HidePlaceholderImage()
650 {
651   if(mPlaceholderVisual)
652   {
653     DevelControl::UnregisterVisual(*this, Toolkit::ImageView::Property::PLACEHOLDER_IMAGE);
654
655     // Hide placeholder
656     Actor self = Self();
657     Toolkit::GetImplementation(mPlaceholderVisual).SetOffScene(self);
658   }
659 }
660
661 void ImageView::TransitionImageWithEffect()
662 {
663   Toolkit::ImageView handle = Toolkit::ImageView(GetOwner());
664
665   if(handle)
666   {
667     mTransitionAnimation = Animation::New(1.5f);
668     mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
669     float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
670
671     if(mPreviousVisual) // Transition previous image
672     {
673       DALI_LOG_ERROR("tscholb : mPreviousVisual !!! \n");
674       Dali::KeyFrames fadeoutKeyFrames = Dali::KeyFrames::New();
675       fadeoutKeyFrames.Add(0.0f, destinationAlpha);
676       fadeoutKeyFrames.Add(1.0f, LOW_OPACITY);
677       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(mPreviousVisual);
678       mTransitionAnimation.AnimateBetween(visualImpl.GetPropertyObject(Toolkit::Visual::Property::OPACITY), fadeoutKeyFrames);
679     }
680     else if(mPlaceholderVisual) // Transition placeholder
681     {
682       DALI_LOG_ERROR("tscholb : mPlaceholderVisual !!! \n");
683       Dali::KeyFrames fadeoutKeyFrames = Dali::KeyFrames::New();
684       fadeoutKeyFrames.Add(0.0f, destinationAlpha);
685       fadeoutKeyFrames.Add(1.0f, LOW_OPACITY);
686       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(mPlaceholderVisual);
687       mTransitionAnimation.AnimateBetween(visualImpl.GetPropertyObject(Toolkit::Visual::Property::OPACITY), fadeoutKeyFrames);
688     }
689
690     // Transition current image
691     Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
692     if(imageVisual)
693     {
694       DALI_LOG_ERROR("tscholb : imageVisual !!! \n");
695       Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
696       fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
697       fadeinKeyFrames.Add(1.0f, destinationAlpha);
698       mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames);
699     }
700
701     // Play transition animation
702     mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
703     mTransitionAnimation.Play();
704   }
705 }
706
707 void ImageView::ClearTransitionAnimation()
708 {
709   // Hide placeholder
710   HidePlaceholderImage();
711
712   // Clear PreviousVisual
713   if(mPreviousVisual)
714   {
715     Actor                    self            = Self();
716     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
717     controlDataImpl.EnableReadyTransitionOverriden(mVisual, false);
718     Toolkit::GetImplementation(mPreviousVisual).SetOffScene(self);
719     mPreviousVisual.Reset();
720   }
721
722   if(mTransitionAnimation)
723   {
724     mTransitionAnimation.FinishedSignal().Disconnect(this, &ImageView::OnTransitionAnimationFinishedCallback);
725     mTransitionAnimation.Clear();
726   }
727 }
728
729 ///////////////////////////////////////////////////////////
730 //
731 // Properties
732 //
733
734 void ImageView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
735 {
736   Toolkit::ImageView imageView = Toolkit::ImageView::DownCast(Dali::BaseHandle(object));
737
738   if(imageView)
739   {
740     ImageView& impl = GetImpl(imageView);
741     switch(index)
742     {
743       case Toolkit::ImageView::Property::IMAGE:
744       {
745         std::string          imageUrl;
746         const Property::Map* map;
747         if(value.Get(imageUrl))
748         {
749           impl.SetImage(imageUrl, ImageDimensions());
750         }
751         // if its not a string then get a Property::Map from the property if possible.
752         else
753         {
754           map = value.GetMap();
755           if(DALI_LIKELY(map))
756           {
757             // the property map is emtpy map. Unregister visual.
758             if(DALI_UNLIKELY(map->Count() == 0u))
759             {
760               impl.ClearImageVisual();
761             }
762             else
763             {
764               Property::Value* shaderValue = map->Find(Toolkit::Visual::Property::SHADER, CUSTOM_SHADER);
765               // set image only if property map contains image information other than custom shader
766               if(map->Count() > 1u || !shaderValue)
767               {
768                 impl.SetImage(*map);
769               }
770               // the property map contains only the custom shader
771               else if((map->Count() == 1u) && (shaderValue))
772               {
773                 Property::Map* shaderMap = shaderValue->GetMap();
774                 if(shaderMap)
775                 {
776                   impl.mShaderMap = *shaderMap;
777
778                   if(!impl.mUrl.empty())
779                   {
780                     impl.SetImage(impl.mUrl, impl.mImageSize);
781                   }
782                   else if(!impl.mPropertyMap.Empty())
783                   {
784                     impl.SetImage(impl.mPropertyMap);
785                   }
786                 }
787               }
788             }
789           }
790           else
791           {
792             // invalid property value comes. Unregister visual.
793             impl.ClearImageVisual();
794           }
795         }
796         break;
797       }
798
799       case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
800       {
801         bool isPre;
802         if(value.Get(isPre))
803         {
804           impl.EnablePreMultipliedAlpha(isPre);
805         }
806         break;
807       }
808
809       case Toolkit::ImageView::Property::PLACEHOLDER_IMAGE:
810       {
811         std::string placeholderUrl;
812         if(value.Get(placeholderUrl))
813         {
814           impl.SetPlaceholderUrl(placeholderUrl);
815         }
816         break;
817       }
818
819       case Toolkit::ImageView::Property::ENABLE_TRANSITION_EFFECT:
820       {
821         bool transitionEffect;
822         if(value.Get(transitionEffect))
823         {
824           impl.EnableTransitionEffect(transitionEffect);
825         }
826         break;
827       }
828     }
829   }
830 }
831
832 Property::Value ImageView::GetProperty(BaseObject* object, Property::Index propertyIndex)
833 {
834   Property::Value value;
835
836   Toolkit::ImageView imageview = Toolkit::ImageView::DownCast(Dali::BaseHandle(object));
837
838   if(imageview)
839   {
840     ImageView& impl = GetImpl(imageview);
841     switch(propertyIndex)
842     {
843       case Toolkit::ImageView::Property::IMAGE:
844       {
845         if(!impl.mUrl.empty())
846         {
847           value = impl.mUrl;
848         }
849         else
850         {
851           Property::Map         map;
852           Toolkit::Visual::Base visual = DevelControl::GetVisual(impl, Toolkit::ImageView::Property::IMAGE);
853           if(visual)
854           {
855             visual.CreatePropertyMap(map);
856           }
857           value = map;
858         }
859         break;
860       }
861
862       case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
863       {
864         value = impl.IsPreMultipliedAlphaEnabled();
865         break;
866       }
867
868       case Toolkit::ImageView::Property::PLACEHOLDER_IMAGE:
869       {
870         value = impl.GetPlaceholderUrl();
871         break;
872       }
873
874       case Toolkit::ImageView::Property::ENABLE_TRANSITION_EFFECT:
875       {
876         value = impl.IsTransitionEffectEnabled();
877         break;
878       }
879     }
880   }
881
882   return value;
883 }
884
885 void ImageView::OnTransitionAnimationFinishedCallback(Animation& animation)
886 {
887   ClearTransitionAnimation();
888 }
889
890 } // namespace Internal
891 } // namespace Toolkit
892 } // namespace Dali