Merge remote-tracking branch 'origin/tizen' into new_text
[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       SetSize( image->GetNaturalSize() );
174       SetPreferredSize( GetTargetSize().GetVectorXY() );
175       mInternalSetSize = false;
176     }
177   }
178 }
179
180 void ImageActor::SetStyle( Style style )
181 {
182   mImageAttachment->SetStyle( style );
183 }
184
185 ImageActor::Style ImageActor::GetStyle() const
186 {
187   return mImageAttachment->GetStyle();
188 }
189
190 void ImageActor::SetNinePatchBorder( const Vector4& border, bool inPixels )
191 {
192   mImageAttachment->SetNinePatchBorder( border, inPixels );
193 }
194
195 Vector4 ImageActor::GetNinePatchBorder() const
196 {
197   return mImageAttachment->GetNinePatchBorder();
198 }
199
200 ImageAttachment& ImageActor::GetImageAttachment()
201 {
202   return *mImageAttachment;
203 }
204
205 RenderableAttachment& ImageActor::GetRenderableAttachment() const
206 {
207   DALI_ASSERT_DEBUG( mImageAttachment && "ImageAttachment missing from ImageActor" );
208   return *mImageAttachment;
209 }
210
211 ImageActor::ImageActor()
212 : RenderableActor(),
213   mUsingNaturalSize(true),
214   mInternalSetSize(false)
215 {
216   // Size negotiate disabled by default, so turn it on for this actor
217   SetRelayoutEnabled( true );
218 }
219
220 ImageActor::~ImageActor()
221 {
222 }
223
224 void ImageActor::SetNaturalSize()
225 {
226   if( mUsingNaturalSize )
227   {
228     mInternalSetSize = true;
229     SetSize( CalculateNaturalSize() );
230     SetPreferredSize( GetTargetSize().GetVectorXY() );
231     mInternalSetSize = false;
232   }
233 }
234
235 Vector3 ImageActor::GetNaturalSize() const
236 {
237   Vector2 naturalSize( CalculateNaturalSize() );
238   return Vector3( naturalSize.width, naturalSize.height, CalculateSizeZ( naturalSize ) );
239 }
240
241 Vector2 ImageActor::CalculateNaturalSize() const
242 {
243   // if no image then natural size is 0
244   Vector2 size( 0.0f, 0.0f );
245
246   ImagePtr image = mImageAttachment->GetImage();
247   if( image )
248   {
249     if( IsPixelAreaSet() )
250     {
251       PixelArea area(GetPixelArea());
252       size.width = area.width;
253       size.height = area.height;
254     }
255     else
256     {
257       size = image->GetNaturalSize();
258     }
259   }
260
261   return size;
262 }
263
264 void ImageActor::OnSizeSet( const Vector3& targetSize )
265 {
266   if( !mInternalSetSize )
267   {
268     mUsingNaturalSize = false;
269   }
270 }
271
272 void ImageActor::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
273 {
274   mUsingNaturalSize = false;
275 }
276
277 void ImageActor::OnStageConnectionInternal()
278 {
279 }
280
281 void ImageActor::OnStageDisconnectionInternal()
282 {
283 }
284
285 unsigned int ImageActor::GetDefaultPropertyCount() const
286 {
287   return RenderableActor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
288 }
289
290 void ImageActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
291 {
292   RenderableActor::GetDefaultPropertyIndices( indices ); // RenderableActor class properties
293
294   indices.reserve( indices.size() + DEFAULT_PROPERTY_COUNT );
295
296   int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
297   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
298   {
299     indices.push_back( index );
300   }
301 }
302
303 bool ImageActor::IsDefaultPropertyWritable( Property::Index index ) const
304 {
305   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
306   {
307     return RenderableActor::IsDefaultPropertyWritable(index);
308   }
309
310   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
311   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
312   {
313     return DEFAULT_PROPERTY_DETAILS[ index ].writable;
314   }
315
316   return false;
317 }
318
319 bool ImageActor::IsDefaultPropertyAnimatable( Property::Index index ) const
320 {
321   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
322   {
323     return RenderableActor::IsDefaultPropertyAnimatable( index );
324   }
325
326   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
327   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
328   {
329     return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
330   }
331
332   return false;
333 }
334
335 bool ImageActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
336 {
337   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
338   {
339     return RenderableActor::IsDefaultPropertyAConstraintInput( index );
340   }
341
342   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
343   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
344   {
345     return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
346   }
347
348   return false;
349 }
350
351 Property::Type ImageActor::GetDefaultPropertyType( Property::Index index ) const
352 {
353   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
354   {
355     return RenderableActor::GetDefaultPropertyType( index );
356   }
357
358   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
359   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
360   {
361     return DEFAULT_PROPERTY_DETAILS[index].type;
362   }
363
364   // index out-of-bounds
365   return Property::NONE;
366 }
367
368 const char* ImageActor::GetDefaultPropertyName( Property::Index index ) const
369 {
370   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
371   {
372     return RenderableActor::GetDefaultPropertyName(index);
373   }
374
375   index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
376   if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
377   {
378     return DEFAULT_PROPERTY_DETAILS[index].name;
379   }
380
381   // index out-of-bounds
382   return NULL;
383 }
384
385 Property::Index ImageActor::GetDefaultPropertyIndex(const std::string& name) const
386 {
387   Property::Index index = Property::INVALID_INDEX;
388
389   // Look for name in default properties
390   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
391   {
392     const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
393     if( 0 == strcmp( name.c_str(), property->name ) ) // Don't want to convert rhs to string
394     {
395       index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
396       break;
397     }
398   }
399
400   // If not found, check in base class
401   if( Property::INVALID_INDEX == index )
402   {
403     index = RenderableActor::GetDefaultPropertyIndex( name );
404   }
405   return index;
406 }
407
408 void ImageActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
409 {
410   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
411   {
412     RenderableActor::SetDefaultProperty( index, propertyValue );
413   }
414   else
415   {
416     switch(index)
417     {
418       case Dali::ImageActor::Property::PIXEL_AREA:
419       {
420         SetPixelArea(propertyValue.Get<Rect<int> >());
421         break;
422       }
423       case Dali::ImageActor::Property::STYLE:
424       {
425         SetStyle( StyleEnum( propertyValue.Get<std::string>() ) );
426         break;
427       }
428       case Dali::ImageActor::Property::BORDER:
429       {
430         SetNinePatchBorder( propertyValue.Get<Vector4>(), true /*in pixels*/ );
431         break;
432       }
433       case Dali::ImageActor::Property::IMAGE:
434       {
435         Dali::Image img = Scripting::NewImage( propertyValue );
436         if(img)
437         {
438           ImagePtr image( &GetImplementation(img) );
439           SetImage( image );
440         }
441         else
442         {
443           DALI_LOG_WARNING("Cannot create image from property value\n");
444         }
445         break;
446       }
447       default:
448       {
449         DALI_LOG_WARNING("Unknown property (%d)\n", index);
450         break;
451       }
452     } // switch(index)
453
454   } // else
455 }
456
457 Property::Value ImageActor::GetDefaultProperty( Property::Index index ) const
458 {
459   Property::Value ret;
460   if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
461   {
462     ret = RenderableActor::GetDefaultProperty( index );
463   }
464   else
465   {
466     switch( index )
467     {
468       case Dali::ImageActor::Property::PIXEL_AREA:
469       {
470         Rect<int> r = GetPixelArea();
471         ret = r;
472         break;
473       }
474       case Dali::ImageActor::Property::STYLE:
475       {
476         ret = StyleString( GetStyle() );
477         break;
478       }
479       case Dali::ImageActor::Property::BORDER:
480       {
481         ret = GetNinePatchBorder();
482         break;
483       }
484       case Dali::ImageActor::Property::IMAGE:
485       {
486         Property::Map map;
487         Scripting::CreatePropertyMap( Dali::Image( mImageAttachment->GetImage().Get() ), map );
488         ret = Property::Value( map );
489         break;
490       }
491       default:
492       {
493         DALI_LOG_WARNING( "Unknown property (%d)\n", index );
494         break;
495       }
496     } // switch(index)
497   }
498
499   return ret;
500 }
501
502 } // namespace Internal
503
504 } // namespace Dali