09093a2bd2b8f6d155ba93df96bf8f5ba35ade0e
[platform/core/uifw/dali-toolkit.git] / plugins / dali-script-v8 / src / controls / control-wrapper.cpp
1 /*
2  * Copyright (c) 2015 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 <actors/actor-wrapper.h>
20 #include "control-wrapper.h"
21
22 // EXTERNAL INCLUDES
23 #include <dali/public-api/object/type-registry.h>
24
25 // INTERNAL INCLUDES
26 #include <controls/item-view-api.h>
27 #include <v8-utils.h>
28 #include <dali-wrapper.h>
29
30 namespace Dali
31 {
32
33 namespace V8Plugin
34 {
35
36 v8::Persistent<v8::ObjectTemplate> ControlWrapper::mControlTemplate;
37 v8::Persistent<v8::ObjectTemplate> ControlWrapper::mItemViewTemplate;
38
39 Vector< void* > ControlWrapper::mControlGarbageContainer;
40
41 namespace
42 {
43
44
45 /**
46  * pointer to a persistent template handle
47  */
48 struct ControlTemplate
49 {
50   v8::Persistent<v8::ObjectTemplate>* controlTemplate;
51 };
52
53 /**
54  * array of templates for each type of control
55  */
56 const ControlTemplate ControlTemplateLookup[]=
57 {
58     { &ControlWrapper::mControlTemplate },        // CONTROL
59     { &ControlWrapper::mItemViewTemplate }        // ITEMVIEW
60 };
61
62 /**
63  * Bitmask of API's that an control can support
64  */
65 enum ControlApiBitMask
66 {
67   CONTROL_API             = 1 << 0,
68   ITEMVIEW_API            = 1 << 1
69 };
70
71 /**
72  * structure used for the ControlApiLookup.
73  */
74 struct ControlApiStruct
75 {
76   const char* controlName;
77   ControlWrapper::ControlType controlType;
78   Toolkit::Control (*constructor)( const v8::FunctionCallbackInfo< v8::Value >& args);
79   int supportApis;
80 };
81
82 /**
83  * Lookup table to match a control type with a constructor and supported API's.
84  * ControlWrapper::ControlType is used to index this table
85  */
86 const ControlApiStruct ControlApiLookup[]=
87 {
88   {"Control",      ControlWrapper::CONTROL,      NULL,                 CONTROL_API },
89   {"ItemView",     ControlWrapper::ITEMVIEW,     ItemViewApi::New,     CONTROL_API | ITEMVIEW_API },
90 };
91
92 const unsigned int ControlApiLookupCount = sizeof(ControlApiLookup)/sizeof(ControlApiLookup[0]);
93
94
95 /**
96  * Creates a control given a type name
97  * Uses the type registry to create an control of the correct type
98  */
99 Toolkit::Control CreateControl( const v8::FunctionCallbackInfo< v8::Value >& args,
100                         const std::string& typeName )
101 {
102   Toolkit::Control control;
103
104   ControlWrapper::ControlType controlType = ControlWrapper::GetControlType( typeName );
105
106   // if we don't currently have specific binding for the given control type,
107   // try to use type registry to create it
108   if( controlType == ControlWrapper::UNKNOWN_CONTROL )
109   {
110     Dali::TypeInfo typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( typeName );
111     if( typeInfo )
112     {
113       Dali::BaseHandle handle = typeInfo.CreateInstance();
114       if( handle )
115       {
116         control = Toolkit::Control::DownCast( handle );
117         if( !control )
118         {
119           DALI_SCRIPT_EXCEPTION( args.GetIsolate(), "Unknown control type" );
120           return Toolkit::Control();
121         }
122       }
123     }
124   }
125   else
126   {
127     // run the constructor for this type of control so it can pull out custom parameters
128     control = (ControlApiLookup[controlType].constructor)( args );
129   }
130
131   return control;
132 }
133
134 /**
135  * given a control type return what api's it supports
136  */
137 int GetControlSupportedApis( ControlWrapper::ControlType type )
138 {
139   return ControlApiLookup[type].supportApis;
140 }
141
142 /**
143  * Used for the ControlFunctionTable to map function names to functions
144  * with for a specific API
145  */
146 struct ControlFunctions
147 {
148   const char* name;               ///< function name
149   void (*function)( const v8::FunctionCallbackInfo< v8::Value >& args);
150   ControlApiBitMask api;
151 };
152
153 /**
154  * Contains a list of all functions that can be called in
155  * ItemView
156  */
157 const ControlFunctions ControlFunctionTable[]=
158 {
159
160     /**************************************
161      * ItemView  API
162      **************************************/
163     { "GetLayoutCount",                  ItemViewApi::GetLayoutCount,                   ITEMVIEW_API  },
164     { "AddLayout",                       ItemViewApi::AddLayout,                        ITEMVIEW_API  },
165     { "RemoveLayout",                    ItemViewApi::RemoveLayout,                     ITEMVIEW_API  },
166     { "ActivateLayout",                  ItemViewApi::ActivateLayout,                   ITEMVIEW_API  },
167     { "GetItemSize",                     ItemViewApi::GetItemSize,                      ITEMVIEW_API  },
168     { "SetItemSize",                     ItemViewApi::SetItemSize,                      ITEMVIEW_API  },
169     { "ScrollToItem",                    ItemViewApi::ScrollToItem,                     ITEMVIEW_API  },
170     { "GetItem",                         ItemViewApi::GetItem,                          ITEMVIEW_API  },
171     { "GetItemId",                       ItemViewApi::GetItemId,                        ITEMVIEW_API  },
172     { "GetItemsRange",                   ItemViewApi::GetItemsRange,                    ITEMVIEW_API  },
173
174 };
175
176 const unsigned int ControlFunctionTableCount = sizeof(ControlFunctionTable)/sizeof(ControlFunctionTable[0]);
177 } //un-named space
178
179
180 ControlWrapper::ControlWrapper( Toolkit::Control control,
181               GarbageCollectorInterface& gc )
182 : ActorWrapper( control, gc ),
183   mControl( control )
184
185 {
186 }
187
188 ControlWrapper::~ControlWrapper()
189 {
190   mControlGarbageContainer.Release();
191 }
192
193 v8::Handle<v8::Object> ControlWrapper::WrapControl(v8::Isolate* isolate, Toolkit::Control control )
194 {
195   v8::EscapableHandleScope handleScope( isolate );
196
197   // Check whether the control is a Control
198   ControlWrapper::ControlType controlType = GetControlType( control.GetTypeName() );
199
200   if( controlType == ControlWrapper::UNKNOWN_CONTROL && Toolkit::Control::DownCast(control) )
201   {
202     controlType = ControlWrapper::CONTROL;
203   }
204
205   v8::Local<v8::Object> object = WrapControl( isolate, control, controlType );
206
207   return handleScope.Escape( object );
208 }
209
210 Toolkit::Control ControlWrapper::GetControl()
211 {
212   return mControl;
213 }
214
215 v8::Handle<v8::Object> ControlWrapper::WrapControl( v8::Isolate* isolate, Toolkit::Control control, ControlType controlType )
216 {
217   v8::EscapableHandleScope handleScope( isolate );
218   v8::Local<v8::ObjectTemplate> objectTemplate;
219
220   objectTemplate = GetControlTemplate( isolate, controlType );
221
222   // create an instance of the template
223   v8::Local<v8::Object> localObject = objectTemplate->NewInstance();
224
225   // create the control object
226   ControlWrapper* pointer = new ControlWrapper( control, Dali::V8Plugin::DaliWrapper::Get().GetDaliGarbageCollector() );
227
228   // assign the JavaScript object to the wrapper.
229   // This also stores Dali object, in an internal field inside the JavaScript object.
230   pointer->SetJavascriptObject( isolate, localObject );
231
232   return handleScope.Escape( localObject );
233 }
234
235 v8::Local<v8::ObjectTemplate> ControlWrapper::GetControlTemplate( v8::Isolate* isolate, ControlWrapper::ControlType type )
236 {
237   v8::EscapableHandleScope handleScope( isolate );
238   v8::Local<v8::ObjectTemplate> objectTemplate;
239
240   if( ControlTemplateLookup[type].controlTemplate->IsEmpty() )
241   {
242     objectTemplate = MakeDaliControlTemplate( isolate, type );
243     ControlTemplateLookup[type].controlTemplate->Reset( isolate, objectTemplate );
244   }
245   else
246   {
247     // get the object template
248     objectTemplate = v8::Local<v8::ObjectTemplate>::New( isolate, *ControlTemplateLookup[type].controlTemplate );
249   }
250
251   return handleScope.Escape( objectTemplate );
252 }
253
254 v8::Handle<v8::ObjectTemplate> ControlWrapper::MakeDaliControlTemplate( v8::Isolate* isolate, ControlType controlType )
255 {
256   v8::EscapableHandleScope handleScope( isolate );
257
258   // all the controls support actor APIs
259   v8::Local<v8::ObjectTemplate> objTemplate = ActorWrapper::MakeDaliActorTemplate( isolate, ActorWrapper::ACTOR );
260
261   // find out what API's this control supports
262   int supportApis = GetControlSupportedApis( controlType );
263
264   // add our function properties
265   for( unsigned int i = 0; i < ControlFunctionTableCount; ++i )
266   {
267     const ControlFunctions property =  ControlFunctionTable[i];
268
269     // check to see if the control supports a certain type of API
270     // e.g. ItemView will support CONTROL_API and ITEMVIEW_API
271     if( supportApis &  property.api )
272     {
273       std::string funcName = V8Utils::GetJavaScriptFunctionName( property.name);
274
275       objTemplate->Set( v8::String::NewFromUtf8( isolate, funcName.c_str() ),
276                       v8::FunctionTemplate::New( isolate, property.function ) );
277     }
278   }
279
280   return handleScope.Escape( objTemplate );
281 }
282
283 void ControlWrapper::NewControl( const v8::FunctionCallbackInfo< v8::Value >& args)
284 {
285   v8::Isolate* isolate = args.GetIsolate();
286   v8::HandleScope handleScope( isolate );
287
288   if( !args.IsConstructCall() )
289   {
290     DALI_SCRIPT_EXCEPTION( isolate, "constructor called without 'new" );
291     return;
292   }
293
294   bool found( false );
295   std::string controlName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate,  args );
296
297   Toolkit::Control control;
298   if( found && controlName != ControlApiLookup[0].controlName )
299   {
300     control = CreateControl( args, controlName ); // create the control with the given type
301   }
302   else
303   {
304     control = Toolkit::Control::New(); // no given type, so create the base type of control
305   }
306
307   if( control )
308   {
309     v8::Local<v8::Object> localObject = WrapControl( isolate, control );
310     args.GetReturnValue().Set( localObject );
311   }
312   else
313   {
314     DALI_SCRIPT_EXCEPTION( isolate, "unsupported control type" );
315   }
316 }
317
318 /**
319  * Given a control type name, e.g. ItemView returns the type, e.g. ControlWrapper::ITEMVIEW
320  */
321 ControlWrapper::ControlType ControlWrapper::GetControlType( const std::string& name )
322 {
323   for( unsigned int i = 0 ; i < ControlApiLookupCount ; i++ )
324   {
325     if( ControlApiLookup[i].controlName == name )
326     {
327       return ControlApiLookup[i].controlType;
328     }
329   }
330   return ControlWrapper::UNKNOWN_CONTROL;
331 }
332
333 void ControlWrapper::RegisterGarbage(void* garbage)
334 {
335   mControlGarbageContainer.PushBack(garbage);
336 }
337
338 } // namespace V8Plugin
339
340 } // namespace Dali