[dali_1.0.14] Merge branch 'tizen'
[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 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 <dali/internal/event/actors/image-actor-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/event/images/nine-patch-image-impl.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/internal/event/common/property-index-ranges.h>
25 #include <dali/internal/event/images/image-connector.h>
26 #include <dali/public-api/scripting/scripting.h>
27
28 namespace Dali
29 {
30
31 const Property::Index ImageActor::PIXEL_AREA           = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
32 const Property::Index ImageActor::STYLE                = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 1;
33 const Property::Index ImageActor::BORDER               = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 2;
34 const Property::Index ImageActor::IMAGE                = Internal::DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT + 3;
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   "style",
55   "border",
56   "image"
57 };
58 const int DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT = sizeof( DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES ) / sizeof( std::string );
59
60 const Property::Type DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT] =
61 {
62   Property::RECTANGLE,  // "pixel-area",
63   Property::STRING,     // "style",
64   Property::VECTOR4,    // "border",
65   Property::MAP,        // "image",
66 };
67
68 ImageActor::Style StyleEnum(const std::string &s)
69 {
70   if(s == "STYLE_NINE_PATCH")
71   {
72     return Dali::ImageActor::STYLE_NINE_PATCH;
73   }
74   else if(s == "STYLE_NINE_PATCH_NO_CENTER")
75   {
76     return Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER;
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 "STYLE_NINE_PATCH";
89   }
90   else if(style == Dali::ImageActor::STYLE_NINE_PATCH_NO_CENTER)
91   {
92     return "STYLE_NINE_PATCH_NO_CENTER";
93   }
94   else // if(s == "QUAD")
95   {
96     return "STYLE_QUAD";
97   }
98 }
99 }
100
101 ImageActorPtr ImageActor::New()
102 {
103   ImageActorPtr actor( new ImageActor );
104
105   // Second-phase construction of base class
106   actor->Initialize();
107
108   // Create the attachment
109   actor->mImageAttachment = ImageAttachment::New( *actor->mNode );
110   actor->Attach( *actor->mImageAttachment );
111
112   return actor;
113 }
114
115 void ImageActor::OnInitialize()
116 {
117   if(ImageActor::mFirstInstance)
118   {
119     mDefaultImageActorPropertyLookup = new DefaultPropertyLookup();
120     const int start = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
121     for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i )
122     {
123       (*mDefaultImageActorPropertyLookup)[DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[i]] = i + start;
124     }
125     ImageActor::mFirstInstance = false;
126   }
127 }
128
129 void ImageActor::SetImage( ImagePtr& image )
130 {
131   ImagePtr currentImage = mImageAttachment->GetImage();
132   // early exit if it's the same image as we already have
133   if ( currentImage == image )
134   {
135     return;
136   }
137
138   // NOTE! image might be pointing to NULL, which is fine as in that case app wants to just remove the image
139   ImagePtr newImage( image );
140   // if image is not NULL, check for 9 patch
141   if( newImage )
142   {
143     // Automatically convert nine-patch images to cropped bitmap
144     NinePatchImage* ninePatchImage = NinePatchImage::DownCast( image.Get() );
145     if( ninePatchImage )
146     {
147       newImage = ninePatchImage->CreateCroppedBitmapImage();
148       SetStyle( Dali::ImageActor::STYLE_NINE_PATCH );
149       SetNinePatchBorder( ninePatchImage->GetStretchBorders(), true );
150     }
151   }
152   // set the actual image (normal or 9 patch) and natural size based on that
153   mImageAttachment->SetImage( newImage );
154   SetNaturalSize();
155 }
156
157 ImagePtr ImageActor::GetImage()
158 {
159   return mImageAttachment->GetImage();
160 }
161
162 void ImageActor::SetToNaturalSize()
163 {
164   mUsingNaturalSize = true;
165
166   SetNaturalSize();
167 }
168
169 void ImageActor::SetPixelArea( const PixelArea& pixelArea )
170 {
171   mImageAttachment->SetPixelArea( pixelArea );
172
173   SetNaturalSize();
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   if( mUsingNaturalSize )
191   {
192     ImagePtr image = mImageAttachment->GetImage();
193     if( image )
194     {
195       mInternalSetSize = true;
196       SetSize( image->GetNaturalSize() );
197       mInternalSetSize = false;
198     }
199   }
200 }
201
202 void ImageActor::SetStyle( Style style )
203 {
204   mImageAttachment->SetStyle( style );
205 }
206
207 ImageActor::Style ImageActor::GetStyle() const
208 {
209   return mImageAttachment->GetStyle();
210 }
211
212 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
213 {
214   mImageAttachment->SetNinePatchBorder( border, inPixels );
215 }
216
217 Vector4 ImageActor::GetNinePatchBorder() const
218 {
219   return mImageAttachment->GetNinePatchBorder();
220 }
221
222 ImageAttachment& ImageActor::GetImageAttachment()
223 {
224   return *mImageAttachment;
225 }
226
227 RenderableAttachment& ImageActor::GetRenderableAttachment() const
228 {
229   DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
230   return *mImageAttachment;
231 }
232
233 ImageActor::ImageActor()
234 : RenderableActor(),
235   mUsingNaturalSize(true),
236   mInternalSetSize(false)
237 {
238 }
239
240 ImageActor::~ImageActor()
241 {
242 }
243
244 void ImageActor::SetNaturalSize()
245 {
246   if( mUsingNaturalSize )
247   {
248     mInternalSetSize = true;
249     SetSize( CalculateNaturalSize() );
250     mInternalSetSize = false;
251   }
252 }
253
254 Vector3 ImageActor::GetNaturalSize() const
255 {
256   Vector2 naturalSize( CalculateNaturalSize() );
257   return Vector3( naturalSize.width, naturalSize.height, CalculateSizeZ( naturalSize ) );
258 }
259
260 Vector2 ImageActor::CalculateNaturalSize() const
261 {
262   // if no image then natural size is 0
263   Vector2 size( 0.0f, 0.0f );
264
265   ImagePtr image = mImageAttachment->GetImage();
266   if( image )
267   {
268     if( IsPixelAreaSet() )
269     {
270       PixelArea area(GetPixelArea());
271       size.width = area.width;
272       size.height = area.height;
273     }
274     else
275     {
276       size = image->GetNaturalSize();
277     }
278   }
279
280   return size;
281 }
282
283 void ImageActor::OnSizeSet( const Vector3& targetSize )
284 {
285   if( !mInternalSetSize )
286   {
287     mUsingNaturalSize = false;
288   }
289 }
290
291 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
292 {
293   mUsingNaturalSize = false;
294 }
295
296 void ImageActor::OnStageConnectionInternal()
297 {
298 }
299
300 void ImageActor::OnStageDisconnectionInternal()
301 {
302 }
303
304 unsigned int ImageActor::GetDefaultPropertyCount() const
305 {
306   return RenderableActor::GetDefaultPropertyCount() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT;
307 }
308
309 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
310 {
311   RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
312
313   indices.reserve( indices.size() + DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT );
314
315   int index = DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
316   for ( int i = 0; i < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT; ++i, ++index )
317   {
318     indices.push_back( index );
319   }
320 }
321
322 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
323 {
324   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
325   {
326     return RenderableActor::IsDefaultPropertyWritable(index);
327   }
328   else
329   {
330     return true;
331   }
332 }
333
334 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
335 {
336   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
337   {
338     return RenderableActor::IsDefaultPropertyAnimatable(index);
339   }
340   else
341   {
342     return false;
343   }
344 }
345
346 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
347 {
348   if( index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT )
349   {
350     return RenderableActor::IsDefaultPropertyAConstraintInput(index);
351   }
352   return true; // Our properties can be used as input to constraints.
353 }
354
355 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
356 {
357   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
358   {
359     return RenderableActor::GetDefaultPropertyType(index);
360   }
361   else
362   {
363     index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
364
365     if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
366     {
367       return DEFAULT_IMAGE_ACTOR_PROPERTY_TYPES[index];
368     }
369     else
370     {
371       // index out-of-bounds
372       return Property::NONE;
373     }
374   }
375 }
376
377 const std::string& ImageActor::GetDefaultPropertyName( Property::Index index ) const
378 {
379   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
380   {
381     return RenderableActor::GetDefaultPropertyName(index);
382   }
383   else
384   {
385     index -= DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT;
386
387     if ( ( index >= 0 ) && ( index < DEFAULT_IMAGE_ACTOR_PROPERTY_COUNT ) )
388     {
389       return DEFAULT_IMAGE_ACTOR_PROPERTY_NAMES[index];
390     }
391     else
392     {
393       // index out-of-bounds
394       static const std::string INVALID_PROPERTY_NAME;
395       return INVALID_PROPERTY_NAME;
396     }
397   }
398 }
399
400 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
401 {
402   Property::Index index = Property::INVALID_INDEX;
403
404   DALI_ASSERT_DEBUG( NULL != mDefaultImageActorPropertyLookup );
405
406   // Look for name in current class' default properties
407   DefaultPropertyLookup::const_iterator result = mDefaultImageActorPropertyLookup->find( name );
408   if ( mDefaultImageActorPropertyLookup->end() != result )
409   {
410     index = result->second;
411   }
412   else
413   {
414     // If not found, check in base class
415     index = RenderableActor::GetDefaultPropertyIndex( name );
416   }
417
418   return index;
419 }
420
421 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
422 {
423   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
424   {
425     RenderableActor::SetDefaultProperty(index, propertyValue);
426   }
427   else
428   {
429     switch(index)
430     {
431       case Dali::ImageActor::PIXEL_AREA:
432       {
433         SetPixelArea(propertyValue.Get<Rect<int> >());
434         break;
435       }
436       case Dali::ImageActor::STYLE:
437       {
438         SetStyle(StyleEnum(propertyValue.Get<std::string>()));
439         break;
440       }
441       case Dali::ImageActor::BORDER:
442       {
443         SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
444         break;
445       }
446       case Dali::ImageActor::IMAGE:
447       {
448         Dali::Image img = Scripting::NewImage( propertyValue );
449         if(img)
450         {
451           ImagePtr image( &GetImplementation(img) );
452           SetImage( image );
453         }
454         else
455         {
456           DALI_LOG_WARNING("Cannot create image from property value\n");
457         }
458         break;
459       }
460       default:
461       {
462         DALI_LOG_WARNING("Unknown property (%d)\n", index);
463         break;
464       }
465     } // switch(index)
466
467   } // else
468 }
469
470 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
471 {
472   Property::Value ret;
473   if(index < DEFAULT_RENDERABLE_ACTOR_PROPERTY_MAX_COUNT)
474   {
475     ret = RenderableActor::GetDefaultProperty(index);
476   }
477   else
478   {
479     switch(index)
480     {
481       case Dali::ImageActor::PIXEL_AREA:
482       {
483         Rect<int> r = GetPixelArea();
484         ret = r;
485         break;
486       }
487       case Dali::ImageActor::STYLE:
488       {
489         ret = StyleString(GetStyle());
490         break;
491       }
492       case Dali::ImageActor::BORDER:
493       {
494         ret = GetNinePatchBorder();
495         break;
496       }
497       case Dali::ImageActor::IMAGE:
498       {
499         Property::Map map;
500         Scripting::CreatePropertyMap( Dali::Image( mImageAttachment->GetImage().Get() ), map );
501         ret = Property::Value( map );
502         break;
503       }
504       default:
505       {
506         DALI_LOG_WARNING("Unknown property (%d)\n", index);
507         break;
508       }
509     } // switch(index)
510   }
511
512   return ret;
513 }
514
515 } // namespace Internal
516
517 } // namespace Dali