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