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