[SRUK] Initial copy from Tizen 2.2 version
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / image-actor-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/event/actors/image-actor-impl.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/public-api/object/type-registry.h>
22 #include <dali/internal/event/common/property-index-ranges.h>
23 #include <dali/internal/event/images/image-connector.h>
24 #include <dali/public-api/scripting/scripting.h>
25
26 namespace Dali
27 {
28
29 const Property::Index ImageActor::PIXEL_AREA           = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT;
30 const Property::Index ImageActor::FADE_IN              = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT + 1;
31 const Property::Index ImageActor::FADE_IN_DURATION     = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT + 2;
32 const Property::Index ImageActor::STYLE                = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT + 3;
33 const Property::Index ImageActor::BORDER               = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT + 4;
34 const Property::Index ImageActor::IMAGE                = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT + 5;
35
36 namespace Internal
37 {
38 bool ImageActor::mFirstInstance = true;
39 Actor::DefaultPropertyLookup* ImageActor::mDefaultImageActorPropertyLookup = NULL;
40
41 namespace
42 {
43
44 BaseHandle Create()
45 {
46   return Dali::ImageActor::New();
47 }
48
49 TypeRegistration mType( typeid(Dali::ImageActor), typeid(Dali::RenderableActor), Create );
50
51 const std::string DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[] =
52 {
53   "pixel-area",
54   "fade-in",
55   "fade-in-duration",
56   "style",
57   "border",
58   "image"
59 };
60 const int DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT = sizeof( DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES ) / sizeof( std::string );
61
62 const Property::Type DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT] =
63 {
64   Property::RECTANGLE,  // "pixel-area",
65   Property::BOOLEAN,    // "fade-in",
66   Property::FLOAT,      // "fade-in-duration",
67   Property::STRING,     // "style",
68   Property::VECTOR4,    // "border",
69   Property::MAP,        // "image",
70 };
71
72 ImageActor::Style StyleEnum(const std::string &s)
73 {
74   if(s == "NINE_PATCH")
75   {
76     return Dali::ImageActor::STYLE_NINE_PATCH;
77   }
78   else // if(s == "QUAD")
79   {
80     return Dali::ImageActor::STYLE_QUAD;
81   }
82 }
83
84 std::string StyleString(const ImageActor::Style style)
85 {
86   if(style == Dali::ImageActor::STYLE_NINE_PATCH)
87   {
88     return "NINE_PATCH";
89   }
90   else // if(s == "QUAD")
91   {
92     return "STYLE_QUAD";
93   }
94 }
95
96 }
97
98 ImageActorPtr ImageActor::New( Image* image )
99 {
100   ImageActorPtr actor( new ImageActor() );
101
102   // Second-phase construction
103   actor->Initialize();
104
105   // Create the attachment
106   actor->mImageAttachment = ImageAttachment::New( *actor->mNode, image );
107   actor->Attach( *actor->mImageAttachment );
108
109   // Adjust the actor's size
110   if( image )
111   {
112     actor->mImageNext.Set( image, false );
113     actor->OnImageSet( *image );
114   }
115
116   return actor;
117 }
118
119 ImageActorPtr ImageActor::New( Image* image, const PixelArea& pixelArea )
120 {
121   // re-use basic New
122   ImageActorPtr actor = New( image );
123   // then set the pixel area
124   actor->mImageAttachment->SetPixelArea( pixelArea );
125   return actor;
126 }
127
128 void ImageActor::OnInitialize()
129 {
130   if(ImageActor::mFirstInstance)
131   {
132     mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
133     const int start = RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT;
134     for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
135     {
136       (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
137     }
138     ImageActor::mFirstInstance = false;
139   }
140 }
141
142 void ImageActor::SetImage( Image* image )
143 {
144   Image* currentImage = static_cast<Image*>(mImageAttachment->GetImage().GetObjectPtr());
145   // early exit if it's the same image
146   if ( currentImage == image || mImageNext.Get() == image )
147   {
148     return;
149   }
150
151   mLoadedConnection.DisconnectAll();
152
153   mImageNext.Set( image, OnStage() );
154
155   if ( image == NULL )
156   {
157     mImageAttachment->SetImage( NULL );
158   }
159   else
160   {
161     // don't disconnect currently shown image until we made sure that the new one is loaded
162     OnImageSet( *image );
163   }
164 }
165
166 Dali::Image ImageActor::GetImage()
167 {
168   return mImageAttachment->GetImage();
169 }
170
171 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
172 {
173   mImageAttachment->SetPixelArea( pixelArea );
174 }
175
176 const ImageActor::PixelArea& ImageActor::GetPixelArea() const
177 {
178   return mImageAttachment->GetPixelArea();
179 }
180
181 bool ImageActor::IsPixelAreaSet() const
182 {
183   return mImageAttachment->IsPixelAreaSet();
184 }
185
186 void ImageActor::ClearPixelArea()
187 {
188   mImageAttachment->ClearPixelArea();
189 }
190
191 void ImageActor::SetStyle( Style style )
192 {
193   mImageAttachment->SetStyle( style );
194 }
195
196 ImageActor::Style ImageActor::GetStyle() const
197 {
198   return mImageAttachment->GetStyle();
199 }
200
201 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
202 {
203   mImageAttachment->SetNinePatchBorder( border, inPixels );
204 }
205
206 Vector4 ImageActor::GetNinePatchBorder() const
207 {
208   return mImageAttachment->GetNinePatchBorder();
209 }
210
211 void ImageActor::SetFadeIn( bool enableFade )
212 {
213   mFadeIn = enableFade;
214 }
215
216 bool ImageActor::GetFadeIn() const
217 {
218   return mFadeIn;
219 }
220
221 void ImageActor::SetFadeInDuration( float durationSeconds )
222 {
223   mFadeInDuration = durationSeconds;
224 }
225
226 float ImageActor::GetFadeInDuration() const
227 {
228   return mFadeInDuration;
229 }
230
231 ImageAttachment& ImageActor::GetImageAttachment()
232 {
233   return *mImageAttachment;
234 }
235
236 Vector2 ImageActor::GetCurrentImageSize() const
237 {
238   Vector3 size;
239   Vector3 currentSize;
240
241   // get the texture size / pixel area if only a subset of it is displayed
242   if (IsPixelAreaSet())
243   {
244     PixelArea area(GetPixelArea());
245     return Vector2(area.width, area.height );
246   }
247   else
248   {
249     return Vector2( GetCurrentSize() );
250   }
251 }
252
253 RenderableAttachment& ImageActor::GetRenderableAttachment() const
254 {
255   DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
256   return *mImageAttachment;
257 }
258
259 ImageActor::ImageActor()
260 : RenderableActor(),
261   mCustomSizeSet( false ),
262   mFadeIn( false ),
263   mFadeInitial( true ),
264   mLoadedConnection( this ),
265   mFadeInDuration( 1.0f )
266 {
267 }
268
269 ImageActor::~ImageActor()
270 {
271   // ScopedConnection disconnects automatically
272 }
273
274 void ImageActor::OnImageSet( Image& image )
275 {
276   // observe image loaded
277   if( Dali::ResourceLoadingSucceeded == image.GetLoadingState() )
278   {
279     //image already loaded
280     ImageLoaded( Dali::Image(&image) );
281   }
282   else
283   {
284     image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
285   }
286 }
287
288 void ImageActor::OnSizeSet( const Vector3& targetSize )
289 {
290   // True if SizeSet() has ever been called
291   mCustomSizeSet = true;
292 }
293
294 void ImageActor::OnStageConnectionInternal()
295 {
296   FadeIn();
297
298   mImageNext.OnStageConnect();
299 }
300
301 void ImageActor::OnStageDisconnectionInternal()
302 {
303   mImageNext.OnStageDisconnect();
304 }
305
306 void ImageActor::ImageLoaded( Dali::Image image )
307 {
308   DALI_ASSERT_DEBUG (image && "Image handle empty!");
309
310   // TODO: Handle case where image loading failed
311
312   // Need to keep mUploadedConnection connected as image may change later through Reload
313   // Note: Reloaded images may have changed size.
314
315   // Set the attachment's image once we know the image has loaded to prevent
316   // blank frames during load / reload.
317   mImageAttachment->SetImage( &GetImplementation( image ) );
318
319   // If size has never been set
320   if( !mCustomSizeSet )
321   {
322     // If a pixel area has been set, use this size
323     if (mImageAttachment->IsPixelAreaSet())
324     {
325       const PixelArea& area = mImageAttachment->GetPixelArea();
326       SetSize(area.width, area.height);
327     }
328     else
329     {
330       SetSize(image.GetWidth(), image.GetHeight());
331     }
332   }
333
334   // fade in if required
335   FadeIn();
336 }
337
338 void ImageActor::FadeIn()
339 {
340   // only fade in if enabled and newly displayed on screen
341   if( mFadeIn && mFadeInitial && ( mFadeInDuration > 0.0f ) )
342   {
343     // need to set opacity immediately to 0 otherwise child actors might get rendered
344     SetOpacity( 0.0f );
345
346     Dali::Image image = mImageAttachment->GetImage();
347
348     // Fade-in when on-stage & the image is loaded
349     if (OnStage() &&
350         image &&
351         image.GetLoadingState() == Dali::ResourceLoadingSucceeded)
352     {
353       // fire and forget animation; will clean up after it's finished
354       Dali::Animation animation = Dali::Animation::New( mFadeInDuration );
355       animation.OpacityTo( Dali::Actor( this ), 1.0f, AlphaFunctions::EaseOut );
356       animation.Play();
357       mFadeInitial = false;
358     }
359   }
360 }
361
362 unsigned int ImageActor::GetDefaultPropertyCount() const
363 {
364   return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
365 }
366
367 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
368 {
369   if(static_cast<unsigned int>(index) < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
370   {
371     return RenderableActor::IsDefaultPropertyWritable(index);
372   }
373   else
374   {
375     return true;
376   }
377 }
378
379 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
380 {
381   if(static_cast<unsigned int>(index) < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
382   {
383     return RenderableActor::IsDefaultPropertyAnimatable(index);
384   }
385   else
386   {
387     return false;
388   }
389 }
390
391 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
392 {
393   if(static_cast<unsigned int>(index) < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
394   {
395     return RenderableActor::GetDefaultPropertyType(index);
396   }
397   else
398   {
399     // ProxyObject guarantees that index is within range
400     return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index - RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT];
401   }
402 }
403
404 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
405 {
406   if(static_cast<unsigned int>(index) < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
407   {
408     return RenderableActor::GetDefaultPropertyName(index);
409   }
410   else
411   {
412     // ProxyObject guarantees that index is within range
413     return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index - RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT];
414   }
415 }
416
417 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
418 {
419   Property::Index index = Property::INVALID_INDEX;
420
421   DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
422
423   // Look for name in current class' default properties
424   DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
425   if ( mDefaultImageActorPropertyLookup->end() != result )
426   {
427     index = result->second;
428   }
429   else
430   {
431     // If not found, check in base class
432     index = RenderableActor::GetDefaultPropertyIndex( name );
433   }
434
435   return index;
436 }
437
438 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
439 {
440   // ProxyObject guarantees the property is writable and index is in range
441
442   if(index < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
443   {
444     RenderableActor::SetDefaultProperty(index, propertyValue);
445   }
446   else
447   {
448     switch(index)
449     {
450       case Dali::ImageActor::PIXEL_AREA:
451       {
452         SetPixelArea(propertyValue.Get<Rect<int> >());
453         break;
454       }
455       case Dali::ImageActor::FADE_IN:
456       {
457         SetFadeIn(propertyValue.Get<bool>());
458         break;
459       }
460       case Dali::ImageActor::FADE_IN_DURATION:
461       {
462         SetFadeInDuration(propertyValue.Get<float>());
463         break;
464       }
465       case Dali::ImageActor::STYLE:
466       {
467         SetStyle(StyleEnum(propertyValue.Get<std::string>()));
468         break;
469       }
470       case Dali::ImageActor::BORDER:
471       {
472         SetNinePatchBorder(propertyValue.Get<Vector4>());
473         break;
474       }
475       case Dali::ImageActor::IMAGE:
476       {
477         Dali::Image img = Scripting::NewImage( propertyValue );
478         if(img)
479         {
480           SetImage( &GetImplementation(img) );
481         }
482         else
483         {
484           DALI_LOG_WARNING("Cannot create image from property value\n");
485         }
486         break;
487       }
488       default:
489       {
490         DALI_LOG_WARNING("Unknown property (%d)\n", index);
491         break;
492       }
493     } // switch(index)
494
495   } // else
496 }
497
498 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
499 {
500   Property::Value ret;
501   if(index < RENDERABLE_ACTOR_DEFAULT_PROPERTY_MAX_COUNT)
502   {
503     ret = RenderableActor::GetDefaultProperty(index);
504   }
505   else
506   {
507     switch(index)
508     {
509       case Dali::ImageActor::PIXEL_AREA:
510       {
511         Rect<int> r = GetPixelArea();
512         ret = r;
513         break;
514       }
515       case Dali::ImageActor::FADE_IN:
516       {
517         ret = GetFadeIn();
518         break;
519       }
520       case Dali::ImageActor::FADE_IN_DURATION:
521       {
522         ret = GetFadeInDuration();
523         break;
524       }
525       case Dali::ImageActor::STYLE:
526       {
527         ret = StyleString(GetStyle());
528         break;
529       }
530       case Dali::ImageActor::BORDER:
531       {
532         ret = GetNinePatchBorder();
533         break;
534       }
535       case Dali::ImageActor::IMAGE:
536       {
537         ret = Property::Value(Property::MAP);
538         break;
539       }
540       default:
541       {
542         DALI_LOG_WARNING("Unknown property (%d)\n", index);
543         break;
544       }
545     } // switch(index)
546   }
547
548   return ret;
549 }
550
551
552 } // namespace Internal
553
554 } // namespace Dali