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