[dali_1.3.16] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / devel-api / scripting / scripting.cpp
1 /*
2  * Copyright (c) 2016 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/devel-api/scripting/scripting.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/object/property-array.h>
26 #include <dali/internal/common/image-attributes.h>
27 #include <dali/internal/event/common/property-helper.h>
28 #include <dali/internal/event/images/resource-image-impl.h>
29 #include <dali/internal/event/images/frame-buffer-image-impl.h>
30 #include <dali/internal/event/images/buffer-image-impl.h>
31
32 namespace Dali
33 {
34
35 namespace Scripting
36 {
37
38 namespace
39 {
40
41 const StringEnum PIXEL_FORMAT_TABLE[] =
42 {
43   { "A8",                                           Pixel::A8                                           },
44   { "L8",                                           Pixel::L8                                           },
45   { "LA88",                                         Pixel::LA88                                         },
46   { "RGB565",                                       Pixel::RGB565                                       },
47   { "BGR565",                                       Pixel::BGR565                                       },
48   { "RGBA4444",                                     Pixel::RGBA4444                                     },
49   { "BGRA4444",                                     Pixel::BGRA4444                                     },
50   { "RGBA5551",                                     Pixel::RGBA5551                                     },
51   { "BGRA5551",                                     Pixel::BGRA5551                                     },
52   { "RGB888",                                       Pixel::RGB888                                       },
53   { "RGB8888",                                      Pixel::RGB8888                                      },
54   { "BGR8888",                                      Pixel::BGR8888                                      },
55   { "RGBA8888",                                     Pixel::RGBA8888                                     },
56   { "BGRA8888",                                     Pixel::BGRA8888                                     },
57   { "COMPRESSED_R11_EAC",                           Pixel::COMPRESSED_R11_EAC                           },
58   { "COMPRESSED_SIGNED_R11_EAC",                    Pixel::COMPRESSED_SIGNED_R11_EAC                    },
59   { "COMPRESSED_SIGNED_RG11_EAC",                   Pixel::COMPRESSED_SIGNED_RG11_EAC                   },
60   { "COMPRESSED_RG11_EAC",                          Pixel::COMPRESSED_RG11_EAC                          },
61   { "COMPRESSED_RGB8_ETC2",                         Pixel::COMPRESSED_RGB8_ETC2                         },
62   { "COMPRESSED_SRGB8_ETC2",                        Pixel::COMPRESSED_SRGB8_ETC2                        },
63   { "COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2",     Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2     },
64   { "COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2",    Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2    },
65   { "COMPRESSED_RGBA8_ETC2_EAC",                    Pixel::COMPRESSED_RGBA8_ETC2_EAC                    },
66   { "COMPRESSED_SRGB8_ALPHA8_ETC2_EAC",             Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC             },
67   { "COMPRESSED_RGB8_ETC1",                         Pixel::COMPRESSED_RGB8_ETC1                         },
68   { "COMPRESSED_RGB_PVRTC_4BPPV1",                  Pixel::COMPRESSED_RGB_PVRTC_4BPPV1                  },
69 };
70 const unsigned int PIXEL_FORMAT_TABLE_COUNT = sizeof( PIXEL_FORMAT_TABLE ) / sizeof( PIXEL_FORMAT_TABLE[0] );
71
72 const StringEnum IMAGE_FITTING_MODE_TABLE[] =
73 {
74   { "SHRINK_TO_FIT", FittingMode::SHRINK_TO_FIT },
75   { "SCALE_TO_FILL", FittingMode::SCALE_TO_FILL },
76   { "FIT_WIDTH",     FittingMode::FIT_WIDTH    },
77   { "FIT_HEIGHT",    FittingMode::FIT_HEIGHT   },
78 };
79 const unsigned int IMAGE_FITTING_MODE_TABLE_COUNT = sizeof( IMAGE_FITTING_MODE_TABLE ) / sizeof( IMAGE_FITTING_MODE_TABLE[0] );
80
81 const StringEnum IMAGE_SAMPLING_MODE_TABLE[] =
82 {
83   { "BOX",              SamplingMode::BOX            },
84   { "NEAREST",          SamplingMode::NEAREST        },
85   { "LINEAR",           SamplingMode::LINEAR         },
86   { "BOX_THEN_NEAREST", SamplingMode::BOX_THEN_NEAREST },
87   { "BOX_THEN_LINEAR",  SamplingMode::BOX_THEN_LINEAR  },
88   { "NO_FILTER",        SamplingMode::NO_FILTER       },
89   { "DONT_CARE",        SamplingMode::DONT_CARE       },
90 };
91 const unsigned int IMAGE_SAMPLING_MODE_TABLE_COUNT = sizeof( IMAGE_SAMPLING_MODE_TABLE ) / sizeof( IMAGE_SAMPLING_MODE_TABLE[0] );
92
93 const char* ImageTypeName[] = { "ResourceImage", "FrameBufferImage", "BufferImage" };
94 enum ImageType                { RESOURCE_IMAGE,  FRAME_BUFFER_IMAGE, BUFFER_IMAGE };
95 const unsigned int imageTypeCount = sizeof( ImageTypeName ) / sizeof( const char* );
96
97 } // unnamed namespace
98
99 bool EnumStringToInteger( const char * const value, const StringEnum* const enumTable, unsigned int tableCount, int& integerEnum )
100 {
101   int ret = 0;
102
103   bool found = false;
104   bool done = false;
105
106   if( value && enumTable && tableCount )
107   {
108     const char* pValue = value;
109
110     while(!done)
111     {
112       size_t size = 0;
113
114       const StringEnum* table = enumTable;
115
116       for ( unsigned int i = 0; i < tableCount; ++i )
117       {
118         if( Internal::CompareTokens( pValue, table->string, size ) )
119         {
120           found = true;
121           ret |= table->value;
122           break;
123         }
124         table++;
125       }
126
127       done = true;
128
129       if(found)
130       {
131         // allow comma separated or'd value
132         if( *(pValue+size) == ',' )
133         {
134           pValue += size + 1;
135           done = false;
136         }
137       }
138
139     }
140
141     integerEnum = ret;
142   }
143
144   if ( !found )
145   {
146     DALI_LOG_ERROR( "Unknown enumeration string %s\n", value );
147   }
148   return found;
149 }
150
151 unsigned int FindEnumIndex( const char* value, const StringEnum* table, unsigned int tableCount )
152 {
153   unsigned int index = 0;
154   bool found = false;
155   for ( unsigned int i = 0; i < tableCount; ++i, ++index )
156   {
157     size_t sizeIgnored = 0;
158     if( Internal::CompareTokens( value, table->string, sizeIgnored ) )
159     {
160       found = true;
161       break;
162     }
163     ++table;
164   }
165   if ( !found )
166   {
167     DALI_LOG_ERROR( "Unknown enumeration string %s\n", value );
168   }
169   return index;
170 }
171
172
173 Image NewImage( const Property::Value& property )
174 {
175   Image ret;
176
177   std::string filename;
178   Internal::ImageAttributes attributes = Internal::ImageAttributes::New();
179
180   const Property::Map* map = property.GetMap();
181   ImageType imageType = RESOURCE_IMAGE; // default to resource image
182   if( map )
183   {
184     // first check the type as it determines, which other parameters are needed
185     const Property::Value* value = map->Find( "type" );
186     if( value )
187     {
188       std::string type;
189       value->Get( type );
190       for( unsigned int i = 0; i < imageTypeCount; ++i )
191       {
192         if( 0 == type.compare( ImageTypeName[ i ] ) )
193         {
194           imageType = static_cast<ImageType>( i );
195           break;
196         }
197       }
198     }
199
200     // filename is only needed for resource images
201     if( RESOURCE_IMAGE == imageType )
202     {
203       const Property::Value* value = map->Find( "filename" );
204       if( value )
205       {
206         value->Get( filename );
207       }
208       // if empty file, no need to go further
209       if( filename.size() == 0 )
210       {
211         DALI_LOG_ERROR( "No filename\n" );
212         return Image();
213       }
214     }
215
216     // Width and height can be set individually. Dali derives the unspecified
217     // dimension from the aspect ratio of the raw image.
218     int width = 0, height = 0;
219
220     value = map->Find( "width" );
221     if( value )
222     {
223       // handle floats and integer the same for json script
224       if( value->GetType() == Property::FLOAT )
225       {
226         width = static_cast<unsigned int>( value->Get<float>() );
227       }
228       else
229       {
230         value->Get( width );
231       }
232     }
233     value = map->Find( "height" );
234     if( value )
235     {
236       if( value->GetType() == Property::FLOAT )
237       {
238         height = static_cast<int>( value->Get<float>() );
239       }
240       else
241       {
242         value->Get( height );
243       }
244     }
245     attributes.SetSize( width, height );
246
247     Pixel::Format pixelFormat = Pixel::RGBA8888;
248     value = map->Find( "pixelFormat" );
249     if( value )
250     {
251       std::string format;
252       value->Get( format );
253       GetEnumeration< Pixel::Format >( format.c_str(), PIXEL_FORMAT_TABLE, PIXEL_FORMAT_TABLE_COUNT, pixelFormat );
254     }
255
256     value = map->Find( "fittingMode" );
257     if( value )
258     {
259       std::string fitting;
260       value->Get( fitting );
261       FittingMode::Type mode;
262       if( GetEnumeration< FittingMode::Type >( fitting.c_str(), IMAGE_FITTING_MODE_TABLE, IMAGE_FITTING_MODE_TABLE_COUNT, mode ) )
263       {
264         attributes.SetScalingMode( mode );
265       }
266     }
267
268     value = map->Find( "samplingMode" );
269     if( value )
270     {
271       std::string sampling;
272       value->Get( sampling );
273       SamplingMode::Type mode;
274       if( GetEnumeration< SamplingMode::Type >( sampling.c_str(), IMAGE_SAMPLING_MODE_TABLE, IMAGE_SAMPLING_MODE_TABLE_COUNT, mode ) )
275       {
276         attributes.SetFilterMode( mode );
277       }
278     }
279
280     value = map->Find( "orientation" );
281     if( value )
282     {
283       bool b = value->Get<bool>();
284       attributes.SetOrientationCorrection( b );
285     }
286
287     switch( imageType )
288     {
289       case RESOURCE_IMAGE :
290       {
291         ret = ResourceImage::New( filename, ImageDimensions( attributes.GetSize().x, attributes.GetSize().y ),
292                                   attributes.GetScalingMode(), attributes.GetFilterMode(), attributes.GetOrientationCorrection() );
293         break;
294       }
295       case BUFFER_IMAGE :
296       {
297         ret = BufferImage::New( attributes.GetWidth(),
298                                 attributes.GetHeight(),
299                                 pixelFormat );
300         break;
301       }
302       case FRAME_BUFFER_IMAGE :
303       {
304         ret = FrameBufferImage::New( attributes.GetWidth(),
305                                      attributes.GetHeight(),
306                                      pixelFormat );
307         break;
308       }
309     }
310   }
311
312   return ret;
313
314 } // Image NewImage( Property::Value map )
315
316
317 Actor NewActor( const Property::Map& map )
318 {
319   BaseHandle handle;
320
321   // First find type and create Actor
322   Property::Value* typeValue = map.Find( "type" );
323   if ( typeValue )
324   {
325     TypeInfo type = TypeRegistry::Get().GetTypeInfo( typeValue->Get< std::string >() );
326     if ( type )
327     {
328       handle = type.CreateInstance();
329     }
330   }
331
332   if ( !handle )
333   {
334     DALI_LOG_ERROR( "Actor type not provided\n" );
335     return Actor();
336   }
337
338   Actor actor( Actor::DownCast( handle ) );
339
340   if ( actor )
341   {
342     // Now set the properties, or create children
343     for ( unsigned int i = 0, mapCount = map.Count(); i < mapCount; ++i )
344     {
345       const KeyValuePair pair( map.GetKeyValue( i ) );
346       if( pair.first.type == Property::Key::INDEX )
347       {
348         continue;
349       }
350       const std::string& key( pair.first.stringKey );
351       if ( key == "type" )
352       {
353         continue;
354       }
355
356       const Property::Value& value( pair.second );
357
358       if ( key == "actors" )
359       {
360         // Create children
361         Property::Array actorArray = value.Get< Property::Array >();
362         for ( Property::Array::SizeType i = 0; i < actorArray.Size(); ++i)
363         {
364           actor.Add( NewActor( actorArray[i].Get< Property::Map >() ) );
365         }
366       }
367       else
368       {
369         Property::Index index( actor.GetPropertyIndex( key ) );
370
371         if ( index != Property::INVALID_INDEX )
372         {
373           actor.SetProperty( index, value );
374         }
375       }
376     }
377   }
378
379   return actor;
380 }
381
382 void CreatePropertyMap( Actor actor, Property::Map& map )
383 {
384   map.Clear();
385
386   if ( actor )
387   {
388     map[ "type" ] = actor.GetTypeName();
389
390     // Default properties
391     Property::IndexContainer indices;
392     actor.GetPropertyIndices( indices );
393     const Property::IndexContainer::ConstIterator endIter = indices.End();
394
395     for ( Property::IndexContainer::Iterator iter = indices.Begin(); iter != endIter; ++iter )
396     {
397       map[ actor.GetPropertyName( *iter ) ] = actor.GetProperty( *iter );
398     }
399
400     // Children
401     unsigned int childCount( actor.GetChildCount() );
402     if ( childCount )
403     {
404       Property::Array childArray;
405       for ( unsigned int child = 0; child < childCount; ++child )
406       {
407         Property::Map childMap;
408         CreatePropertyMap( actor.GetChildAt( child ), childMap );
409         childArray.PushBack( childMap );
410       }
411       map[ "actors" ] = childArray;
412     }
413   }
414 }
415
416 void CreatePropertyMap( Image image, Property::Map& map )
417 {
418   map.Clear();
419
420   if ( image )
421   {
422     std::string imageType( "ResourceImage" );
423
424     // Get Type - cannot use TypeRegistry as Image is not an Object and thus, not registered
425     BufferImage bufferImage = BufferImage::DownCast( image );
426     if ( bufferImage )
427     {
428       imageType = "BufferImage";
429       map[ "pixelFormat" ] = GetEnumerationName< Pixel::Format >( bufferImage.GetPixelFormat(), PIXEL_FORMAT_TABLE, PIXEL_FORMAT_TABLE_COUNT );
430     }
431     else if ( FrameBufferImage::DownCast( image ) )
432     {
433       imageType = "FrameBufferImage";
434     }
435
436     map[ "type" ] = imageType;
437
438     ResourceImage resourceImage = ResourceImage::DownCast( image );
439     if( resourceImage )
440     {
441       map[ "filename" ] = resourceImage.GetUrl();
442     }
443
444     int width( image.GetWidth() );
445     int height( image.GetHeight() );
446
447     if ( width && height )
448     {
449       map[ "width" ] = width;
450       map[ "height" ] = height;
451     }
452   }
453 }
454
455 void NewAnimation( const Property::Map& map, Dali::AnimationData& outputAnimationData )
456 {
457   // Note: Builder cannot currently pass generic Property::Maps "{" that are nested, so currently we can only have one AnimateTo per animation.
458   Dali::AnimationData::AnimationDataElement* element = new Dali::AnimationData::AnimationDataElement();
459   element->alphaFunction = AlphaFunction::LINEAR;
460   element->timePeriodDelay = 0.0f;
461   element->timePeriodDuration = 1.0f;
462
463   // Now set the properties, or create children
464   for( unsigned int i = 0, animationMapCount = map.Count(); i < animationMapCount; ++i )
465   {
466     const KeyValuePair pair( map.GetKeyValue( i ) );
467     if( pair.first.type == Property::Key::INDEX )
468     {
469       continue; // We don't consider index keys.
470     }
471     const std::string& key( pair.first.stringKey );
472
473     const Property::Value& value( pair.second );
474
475     if( key == "actor" )
476     {
477       element->actor = value.Get< std::string >();
478     }
479     else if( key == "property" )
480     {
481       element->property = value.Get< std::string >();
482     }
483     else if( key == "value" )
484     {
485       element->value = value;
486     }
487     else if( key == "alphaFunction" )
488     {
489       std::string alphaFunctionValue = value.Get< std::string >();
490
491       if( alphaFunctionValue == "LINEAR" )
492       {
493         element->alphaFunction = AlphaFunction::LINEAR;
494       }
495       else if( alphaFunctionValue == "REVERSE" )
496       {
497         element->alphaFunction = AlphaFunction::REVERSE;
498       }
499       else if( alphaFunctionValue == "EASE_IN_SQUARE" )
500       {
501         element->alphaFunction = AlphaFunction::EASE_IN_SQUARE;
502       }
503       else if( alphaFunctionValue == "EASE_OUT_SQUARE" )
504       {
505         element->alphaFunction = AlphaFunction::EASE_OUT_SQUARE;
506       }
507       else if( alphaFunctionValue == "EASE_IN" )
508       {
509         element->alphaFunction = AlphaFunction::EASE_IN;
510       }
511       else if( alphaFunctionValue == "EASE_OUT" )
512       {
513         element->alphaFunction = AlphaFunction::EASE_OUT;
514       }
515       else if( alphaFunctionValue == "EASE_IN_OUT" )
516       {
517         element->alphaFunction = AlphaFunction::EASE_IN_OUT;
518       }
519       else if( alphaFunctionValue == "EASE_IN_SINE" )
520       {
521         element->alphaFunction = AlphaFunction::EASE_IN_SINE;
522       }
523       else if( alphaFunctionValue == "EASE_OUT_SINE" )
524       {
525         element->alphaFunction = AlphaFunction::EASE_OUT_SINE;
526       }
527       else if( alphaFunctionValue == "EASE_IN_OUT_SINE" )
528       {
529         element->alphaFunction = AlphaFunction::EASE_IN_OUT_SINE;
530       }
531       else if( alphaFunctionValue == "BOUNCE" )
532       {
533         element->alphaFunction = AlphaFunction::BOUNCE;
534       }
535       else if( alphaFunctionValue == "SIN" )
536       {
537         element->alphaFunction = AlphaFunction::SIN;
538       }
539       else if( alphaFunctionValue == "EASE_OUT_BACK" )
540       {
541         element->alphaFunction = AlphaFunction::EASE_OUT_BACK;
542       }
543     }
544     else if( key == "timePeriod" )
545     {
546       Property::Map timeMap = value.Get< Property::Map >();
547       for( unsigned int i = 0; i < timeMap.Count(); ++i )
548       {
549         const KeyValuePair timePair( timeMap.GetKeyValue( i ) );
550         if( timePair.first.type == Property::Key::INDEX )
551         {
552           continue;
553         }
554         const std::string& key( timePair.first.stringKey );
555
556         if( key == "delay" )
557         {
558           element->timePeriodDelay = timePair.second.Get< float >();
559         }
560         else if( key == "duration" )
561         {
562           element->timePeriodDuration = timePair.second.Get< float >();
563         }
564       }
565     }
566   }
567
568   outputAnimationData.Add( element );
569 }
570
571 } // namespace scripting
572
573 } // namespace Dali