From: Richard Huang Date: Thu, 7 Jan 2016 16:05:12 +0000 (+0000) Subject: JavaScript binding for ItemView X-Git-Tag: dali_1.1.18~10^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=c2d1329e1e2211c372f8a696f7afd69edcdf23df JavaScript binding for ItemView Change-Id: If4ba2434a2ea7a22cacd13d431dbe54bf56540b9 --- diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index aa6443d..86a869e 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -42,21 +42,6 @@ using namespace Dali; namespace // Unnamed namespace { -//Type registration - -DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL) - -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition", FLOAT, LAYOUT_POSITION) -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed", FLOAT, SCROLL_SPEED) -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot", FLOAT, OVERSHOOT) -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollDirection", VECTOR2, SCROLL_DIRECTION) -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutOrientation", INTEGER, LAYOUT_ORIENTATION) -DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollContentSize", FLOAT, SCROLL_CONTENT_SIZE) - -DALI_SIGNAL_REGISTRATION( Toolkit, ItemView, "layoutActivated", LAYOUT_ACTIVATED_SIGNAL ) - -DALI_TYPE_REGISTRATION_END() - const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f; const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f; const float DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f; @@ -256,6 +241,27 @@ namespace Internal namespace // unnamed namespace { +//Type registration + +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL) + +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeSpeed", FLOAT, MINIMUM_SWIPE_SPEED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeDistance", FLOAT, MINIMUM_SWIPE_DISTANCE ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "wheelScrollDistanceStep", FLOAT, WHELL_SCROLL_DISTANCE_SPEED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "snapToItemEnabled", BOOLEAN, SNAP_TO_ITEM_ENABLED ) +DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "refreshInterval", FLOAT, REFRESH_INTERVAL ) + +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition", FLOAT, LAYOUT_POSITION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed", FLOAT, SCROLL_SPEED) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot", FLOAT, OVERSHOOT) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollDirection", VECTOR2, SCROLL_DIRECTION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutOrientation", INTEGER, LAYOUT_ORIENTATION) +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollContentSize", FLOAT, SCROLL_CONTENT_SIZE) + +DALI_SIGNAL_REGISTRATION( Toolkit, ItemView, "layoutActivated", LAYOUT_ACTIVATED_SIGNAL ) + +DALI_TYPE_REGISTRATION_END() + bool FindById( const ItemContainer& items, ItemId id ) { for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter ) @@ -1692,6 +1698,86 @@ bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* return connected; } +void ItemView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +{ + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) ); + + if( itemView ) + { + ItemView& itemViewImpl( GetImpl( itemView ) ); + switch( index ) + { + case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED: + { + itemViewImpl.SetMinimumSwipeSpeed( value.Get() ); + break; + } + case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE: + { + itemViewImpl.SetMinimumSwipeDistance( value.Get() ); + break; + } + case Toolkit::ItemView::Property::WHELL_SCROLL_DISTANCE_SPEED: + { + itemViewImpl.SetWheelScrollDistanceStep( value.Get() ); + break; + } + case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED: + { + itemViewImpl.SetAnchoring( value.Get() ); + break; + } + case Toolkit::ItemView::Property::REFRESH_INTERVAL: + { + itemViewImpl.SetRefreshInterval( value.Get() ); + break; + } + } + } +} + +Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index ) +{ + Property::Value value; + + Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) ); + + if( itemView ) + { + ItemView& itemViewImpl( GetImpl( itemView ) ); + switch( index ) + { + case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED: + { + value = itemViewImpl.GetMinimumSwipeSpeed(); + break; + } + case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE: + { + value = itemViewImpl.GetMinimumSwipeDistance(); + break; + } + case Toolkit::ItemView::Property::WHELL_SCROLL_DISTANCE_SPEED: + { + value = itemViewImpl.GetWheelScrollDistanceStep(); + break; + } + case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED: + { + value = itemViewImpl.GetAnchoring(); + break; + } + case Toolkit::ItemView::Property::REFRESH_INTERVAL: + { + value = itemViewImpl.GetRefreshInterval(); + break; + } + } + } + + return value; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h index a18618d..2b3a52f 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h @@ -308,6 +308,24 @@ public: */ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ); + //properties + + /** + * Called when a property of an object of this type is set. + * @param[in] object The object whose property is set. + * @param[in] index The property index. + * @param[in] value The new property value. + */ + static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ); + + /** + * Called to retrieve a property of an object of this type. + * @param[in] object The object whose property is to be retrieved. + * @param[in] index The property index. + * @return The current value of the property. + */ + static Property::Value GetProperty( BaseObject* object, Property::Index index ); + private: /** diff --git a/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp b/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp index 98ab55b..e1f79ca 100644 --- a/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp @@ -48,7 +48,8 @@ DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Scrollable, Toolkit::Control, Create ); DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootEffectColor", VECTOR4, OVERSHOOT_EFFECT_COLOR ) DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootAnimationSpeed", FLOAT, OVERSHOOT_ANIMATION_SPEED ) -const int OVERSHOOT_SIZE = Dali::Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED + 1; // OVERSHOOT_SIZE is not public yet +DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootEnabled", BOOLEAN, OVERSHOOT_ENABLED ) +const int OVERSHOOT_SIZE = Dali::Toolkit::Scrollable::Property::OVERSHOOT_ENABLED + 1; // OVERSHOOT_SIZE is not public yet Dali::PropertyRegistration p1( typeRegistration, "overshootSize", OVERSHOOT_SIZE, Property::VECTOR2, Dali::Toolkit::Internal::Scrollable::SetProperty, Dali::Toolkit::Internal::Scrollable::GetProperty ); DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scrollRelativePosition", VECTOR2, SCROLL_RELATIVE_POSITION) @@ -194,6 +195,11 @@ void Scrollable::SetProperty( BaseObject* object, Property::Index index, const P scrollableImpl.SetOvershootAnimationSpeed( value.Get() ); break; } + case Toolkit::Scrollable::Property::OVERSHOOT_ENABLED: + { + scrollableImpl.SetOvershootEnabled( value.Get() ); + break; + } case OVERSHOOT_SIZE: // OVERSHOOT_SIZE is not public yet { Vector2 input; @@ -229,6 +235,11 @@ Property::Value Scrollable::GetProperty( BaseObject* object, Property::Index ind value = scrollableImpl.GetOvershootAnimationSpeed(); break; } + case Toolkit::Scrollable::Property::OVERSHOOT_ENABLED: + { + value = scrollableImpl.IsOvershootEnabled(); + break; + } case OVERSHOOT_SIZE: // OVERSHOOT_SIZE is not public yet { value = scrollableImpl.mOvershootSize; diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h b/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h index e790a82..5431d25 100644 --- a/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h +++ b/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h @@ -63,6 +63,9 @@ public: enum PropertyRange { + PROPERTY_START_INDEX = Toolkit::Scrollable::PROPERTY_END_INDEX + 1, ///< @since DALi 1.1.18 + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000, ///< Reserve property indices, @since DALi 1.1.18 + ANIMATABLE_PROPERTY_START_INDEX = Toolkit::Scrollable::ANIMATABLE_PROPERTY_END_INDEX + 1, ANIMATABLE_PROPERTY_END_INDEX = ANIMATABLE_PROPERTY_START_INDEX + 1000 ///< Reserve animatable property indices }; @@ -74,12 +77,20 @@ public: { enum { - LAYOUT_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< Property, name "layoutPosition", type float - SCROLL_SPEED, ///< Property, name "scrollSpeed", type float - OVERSHOOT, ///< Property, name "overshoot", type float - SCROLL_DIRECTION, ///< Property, name "scrollDirection", type Vector2 - LAYOUT_ORIENTATION, ///< Property, name "layoutOrientation", type integer - SCROLL_CONTENT_SIZE ///< Property, name "scrollContentSize", type float + // Event side properties + MINIMUM_SWIPE_SPEED = PROPERTY_START_INDEX, ///< Property, name "minimumSwipeSpeed", @see SetMinimumSwipeSpeed(), type float, @since DALi 1.1.18 + MINIMUM_SWIPE_DISTANCE, ///< Property, name "minimumSwipeDistance", @see SetMinimumSwipeDistance(), type float, @since DALi 1.1.18 + WHELL_SCROLL_DISTANCE_SPEED, ///< Property, name "wheelScrollDistanceStep", @see SetWheelScrollDistanceStep(), type float, @since DALi 1.1.18 + SNAP_TO_ITEM_ENABLED, ///< Property, name "snapToItemEnabled", @see SetAnchoring(), type bool, @since DALi 1.1.18 + REFRESH_INTERVAL, ///< Property, name "refreshInterval", @see SetRefreshInterval(), type float, @since DALi 1.1.18 + + // Animatable properties + LAYOUT_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< Property, name "layoutPosition", type float + SCROLL_SPEED, ///< Property, name "scrollSpeed", type float + OVERSHOOT, ///< Property, name "overshoot", type float + SCROLL_DIRECTION, ///< Property, name "scrollDirection", type Vector2 + LAYOUT_ORIENTATION, ///< Property, name "layoutOrientation", type integer + SCROLL_CONTENT_SIZE ///< Property, name "scrollContentSize", type float }; }; diff --git a/dali-toolkit/public-api/controls/scrollable/scrollable.h b/dali-toolkit/public-api/controls/scrollable/scrollable.h index 76dbb07..3c22468 100644 --- a/dali-toolkit/public-api/controls/scrollable/scrollable.h +++ b/dali-toolkit/public-api/controls/scrollable/scrollable.h @@ -58,8 +58,8 @@ public: */ enum PropertyRange { - PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, - PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000, ///< Reserve property indices + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @since DALi 1.1.18 + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000, ///< Reserve property indices, @since DALi 1.1.18 ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX, ANIMATABLE_PROPERTY_END_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000 ///< Reserve animatable property indices @@ -75,6 +75,7 @@ public: // Event side properties OVERSHOOT_EFFECT_COLOR = PROPERTY_START_INDEX, ///< Property, name "overshootEffectColor", @see SetOvershootEffectColor(), type Vector4 OVERSHOOT_ANIMATION_SPEED, ///< Property, name "overshootAnimationSpeed", @see SetOvershootAnimationSpeed(), type float + OVERSHOOT_ENABLED, ///< Property, name "overshootEnabled", @see SetOvershootEnabled(), type bool, @since DALi 1.1.18 // Animatable properties SCROLL_RELATIVE_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< Property, name "scrollRelativePosition", type Vector2 diff --git a/docs/content/images/item-view/list.png b/docs/content/images/item-view/list.png new file mode 100755 index 0000000..d588929 Binary files /dev/null and b/docs/content/images/item-view/list.png differ diff --git a/node-addon/binding.gyp b/node-addon/binding.gyp index dad473d..142cc74 100644 --- a/node-addon/binding.gyp +++ b/node-addon/binding.gyp @@ -18,6 +18,9 @@ '<(DALI_JS_DIR)/actors/layer-api.cpp', '<(DALI_JS_DIR)/actors/camera-actor-api.cpp', '<(DALI_JS_DIR)/constants/constants-wrapper.cpp', + '<(DALI_JS_DIR)/controls/control-wrapper.cpp', + '<(DALI_JS_DIR)/controls/item-factory-wrapper.cpp', + '<(DALI_JS_DIR)/controls/item-view-api.cpp', '<(DALI_JS_DIR)/animation/animation-api.cpp', '<(DALI_JS_DIR)/animation/animation-wrapper.cpp', '<(DALI_JS_DIR)/animation/constrainer-api.cpp', diff --git a/node-addon/examples/images/icon-0.png b/node-addon/examples/images/icon-0.png new file mode 100755 index 0000000..8d300e9 Binary files /dev/null and b/node-addon/examples/images/icon-0.png differ diff --git a/node-addon/examples/images/icon-1.png b/node-addon/examples/images/icon-1.png new file mode 100755 index 0000000..bfed8ac Binary files /dev/null and b/node-addon/examples/images/icon-1.png differ diff --git a/node-addon/examples/images/icon-2.png b/node-addon/examples/images/icon-2.png new file mode 100755 index 0000000..db892fb Binary files /dev/null and b/node-addon/examples/images/icon-2.png differ diff --git a/node-addon/image-1.jpg b/node-addon/examples/images/image-1.jpg similarity index 100% rename from node-addon/image-1.jpg rename to node-addon/examples/images/image-1.jpg diff --git a/node-addon/image-2.jpg b/node-addon/examples/images/image-2.jpg similarity index 100% rename from node-addon/image-2.jpg rename to node-addon/examples/images/image-2.jpg diff --git a/node-addon/examples/item-view.js b/node-addon/examples/item-view.js new file mode 100644 index 0000000..5abfcfc --- /dev/null +++ b/node-addon/examples/item-view.js @@ -0,0 +1,142 @@ + var window= { + x:0, + y:0, + width:1920, + height: 1080, + transparent: false, + name:'itemview-example' + }; + + var viewMode={ + 'stereoscopic-mode':'mono', // stereo-horizontal, stereo-vertical, stereo-interlaced, + 'stereoBase': 65 // Distance in millimeters between left/right cameras typically between (50-70mm) + }; + + var options= { + 'window': window, + 'viewMode': viewMode, + } + +//desktop +//var dali = require('../build/Release/dali')( options ); + +//target +var dali = require('dali')( options ); + +var items = []; +var button; +var stageSize; + +var itemView; +var itemFactory; + +var currentLayoutIndex = 0; +var totalItemCount = 100; + +var imageDir = "./images/"; + +var daliApp = {}; + +daliApp.createItemView = function() { + + // Create item view data + var itemViewData = []; + for (var itemId = 0; itemId < totalItemCount; itemId++) + { + var data = {}; + data["template"] = "template-item-list"; // Create items initially with list template + data["icon_path"] = imageDir + "icon-" + itemId % 3 + ".png"; + data["title_text"] = "Item " + itemId; + itemViewData[itemId] = data; + } + + // Create item factory and set the data + itemFactory = new dali.ItemFactory(); + itemFactory.jsonTemplateFile = "./scripts/item-template.json"; + itemFactory.data = itemViewData; + + // Create item view + stageSize = dali.stage.getSize(); + itemView = new dali.Control("ItemView", itemFactory); + itemView.size = [stageSize.x, stageSize.y, 0.0]; + itemView.parentOrigin = dali.CENTER_LEFT; + itemView.anchorPoint = dali.CENTER_LEFT; + itemView.refreshInterval = 4.0; + + // Add item view to the stage + dali.stage.add( itemView ); + + // Create scroll bar for item view + var scrollBar = new dali.Control("ScrollBar"); + scrollBar.parentOrigin = dali.TOP_RIGHT; + scrollBar.anchorPoint = dali.TOP_RIGHT; + scrollBar.widthResizePolicy = "FIT_TO_CHILDREN"; + scrollBar.heightResizePolicy = "FILL_TO_PARENT"; + itemView.add(scrollBar); + + // Add the list and grid layouts + itemView.addLayout(dali.ITEM_LAYOUT_LIST); // layout index 0 + itemView.addLayout(dali.ITEM_LAYOUT_GRID); // layout index 1 + + // Set custom item size for list layout + itemView.setItemSize(0, [stageSize.x, stageSize.y * 0.1, 0.0]); + + // Set custom item size for grid layout + var layoutMargin = 120; + itemView.setItemSize(1, [(stageSize.x - layoutMargin) / 4, stageSize.y * 0.2, 0.0]); + + // Activate the list layout + itemView.activateLayout(0, itemView.size); + + // Create button for layout switching + button = new dali.Control("PushButton"); + button.size = [100.0, 60.0, 0.0]; + button.position = [-20.0, 20.0, 0.0]; + button.parentOrigin = dali.TOP_RIGHT; + button.anchorPoint = dali.TOP_RIGHT; + button.labelText = "Switch"; + dali.stage.add( button ); + + // Connect a signal callback to button pressed signal + button.on("pressed", daliApp.buttonPressedEvent); +} + +daliApp.buttonPressedEvent = function( button ) { + + // Calculate the layout index for the next layout to switch to + currentLayoutIndex++; + currentLayoutIndex = currentLayoutIndex % itemView.getLayoutCount(); + + // Activate the next layout + itemView.activateLayout(currentLayoutIndex, [stageSize.x, stageSize.y, 0.0], 0.0); + + // Change the item template in item view data as we want to change the layout of the items + var data = itemFactory.data; + for (var itemId = 0; itemId < totalItemCount; itemId++) + { + if(currentLayoutIndex == 0) + { + // List layout + data[itemId]["template"] = "template-item-list"; // Create items with list template + } + else + { + // Grid layout + data[itemId]["template"] = "template-item-grid"; // Create items with grid template + } + } + itemFactory.data = data; +} + +function startup() +{ + daliApp.init(); +} + +daliApp.init = function() +{ + daliApp.createItemView(); +} + +startup(); + diff --git a/node-addon/line-mesh.js b/node-addon/examples/line-mesh.js similarity index 98% rename from node-addon/line-mesh.js rename to node-addon/examples/line-mesh.js index f1c9532..faaedb9 100644 --- a/node-addon/line-mesh.js +++ b/node-addon/examples/line-mesh.js @@ -18,7 +18,7 @@ } // desktop -//var dali = require('./build/Release/dali')( options ); +//var dali = require('../build/Release/dali')( options ); // target var dali = require('dali')( options ); diff --git a/node-addon/mesh-morph.js b/node-addon/examples/mesh-morph.js similarity index 99% rename from node-addon/mesh-morph.js rename to node-addon/examples/mesh-morph.js index dd4527a..edbdcf9 100644 --- a/node-addon/mesh-morph.js +++ b/node-addon/examples/mesh-morph.js @@ -17,9 +17,8 @@ 'view-mode': viewMode, } - // desktop -//var dali = require('./build/Release/dali')( options ); +//var dali = require('../build/Release/dali')( options ); // target var dali = require('dali')( options ); diff --git a/node-addon/point-mesh.js b/node-addon/examples/point-mesh.js similarity index 98% rename from node-addon/point-mesh.js rename to node-addon/examples/point-mesh.js index f9c7186..ceb9b1e 100644 --- a/node-addon/point-mesh.js +++ b/node-addon/examples/point-mesh.js @@ -17,11 +17,11 @@ 'view-mode': viewMode, } -var imageDir = "./"; +var imageDir = "./images/"; // desktop -//var dali = require('./build/Release/dali')( options ); +//var dali = require('../build/Release/dali')( options ); // target var dali = require('dali')( options ); diff --git a/node-addon/examples/scripts/item-template.json b/node-addon/examples/scripts/item-template.json new file mode 100644 index 0000000..f909edd --- /dev/null +++ b/node-addon/examples/scripts/item-template.json @@ -0,0 +1,92 @@ +{ + "templates": + { + "template-item-list": + { + "name":"item", + "type":"Actor", + "position":[0,0,0], + "anchorPoint":"TOP_LEFT", + "parentOrigin":"TOP_LEFT", + "actors": + [ + { + "name":"icon", + "type":"ImageView", + "image": + { + "rendererType" : "imageRenderer", + "imageUrl": "{icon_path}" + }, + "position":[20.0, 0.0, 0.0], + "size":[70.0, 70.0, 0.0], + "color":[1.0,1.0,1.0,1.0], + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_LEFT", + "actors": + [ + { + "name":"title", + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_RIGHT", + "type":"TextLabel", + "position": [30.0, 0.0, 0.0], + "size":[200.0, 70.0, 0.0], + "pointSize":30, + "fontFamily":"HelveticaNeue", + "fontStyle":"Bold", + "horizontalAlignment":"BEGIN", + "verticalAlignment":"CENTER", + "textColor": [1.0,0.0,1.0,1.0], + "text":"{title_text}" + } + ] + } + ] + }, + + "template-item-grid": + { + "name":"item", + "type":"Actor", + "position":[0,0,0], + "anchorPoint":"TOP_LEFT", + "parentOrigin":"TOP_LEFT", + "actors": + [ + { + "name":"icon", + "type":"ImageView", + "image": + { + "rendererType" : "imageRenderer", + "imageUrl": "{icon_path}" + }, + "position":[0.0, -10.0, 0.0], + "size":[70.0, 70.0, 0.0], + "color":[1.0,1.0,1.0,1.0], + "anchorPoint":"CENTER", + "parentOrigin":"CENTER", + "actors": + [ + { + "name":"title", + "anchorPoint":"TOP_CENTER", + "parentOrigin":"BOTTOM_CENTER", + "type":"TextLabel", + "position": [0.0,10.0,0.0], + "size":[100.0, 100.0, 0.0], + "pointSize":22, + "fontFamily":"HelveticaNeue", + "fontStyle":"Bold", + "horizontalAlignment":"CENTER", + "textColor": [1.0,0.0,1.0,1.0], + "text":"{title_text}" + } + ] + } + ] + } + } +} + diff --git a/node-addon/texture-mesh.js b/node-addon/examples/texture-mesh.js similarity index 98% rename from node-addon/texture-mesh.js rename to node-addon/examples/texture-mesh.js index 7f6173e..016a7a9 100644 --- a/node-addon/texture-mesh.js +++ b/node-addon/examples/texture-mesh.js @@ -17,11 +17,11 @@ 'view-mode': viewMode, } -var imageDir = "./"; +var imageDir = "./images/"; // desktop -//var dali = require('./build/Release/dali')( options ); +//var dali = require('../build/Release/dali')( options ); // target var dali = require('dali')( options ); diff --git a/node-addon/item-template.json b/node-addon/item-template.json new file mode 100644 index 0000000..f909edd --- /dev/null +++ b/node-addon/item-template.json @@ -0,0 +1,92 @@ +{ + "templates": + { + "template-item-list": + { + "name":"item", + "type":"Actor", + "position":[0,0,0], + "anchorPoint":"TOP_LEFT", + "parentOrigin":"TOP_LEFT", + "actors": + [ + { + "name":"icon", + "type":"ImageView", + "image": + { + "rendererType" : "imageRenderer", + "imageUrl": "{icon_path}" + }, + "position":[20.0, 0.0, 0.0], + "size":[70.0, 70.0, 0.0], + "color":[1.0,1.0,1.0,1.0], + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_LEFT", + "actors": + [ + { + "name":"title", + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_RIGHT", + "type":"TextLabel", + "position": [30.0, 0.0, 0.0], + "size":[200.0, 70.0, 0.0], + "pointSize":30, + "fontFamily":"HelveticaNeue", + "fontStyle":"Bold", + "horizontalAlignment":"BEGIN", + "verticalAlignment":"CENTER", + "textColor": [1.0,0.0,1.0,1.0], + "text":"{title_text}" + } + ] + } + ] + }, + + "template-item-grid": + { + "name":"item", + "type":"Actor", + "position":[0,0,0], + "anchorPoint":"TOP_LEFT", + "parentOrigin":"TOP_LEFT", + "actors": + [ + { + "name":"icon", + "type":"ImageView", + "image": + { + "rendererType" : "imageRenderer", + "imageUrl": "{icon_path}" + }, + "position":[0.0, -10.0, 0.0], + "size":[70.0, 70.0, 0.0], + "color":[1.0,1.0,1.0,1.0], + "anchorPoint":"CENTER", + "parentOrigin":"CENTER", + "actors": + [ + { + "name":"title", + "anchorPoint":"TOP_CENTER", + "parentOrigin":"BOTTOM_CENTER", + "type":"TextLabel", + "position": [0.0,10.0,0.0], + "size":[100.0, 100.0, 0.0], + "pointSize":22, + "fontFamily":"HelveticaNeue", + "fontStyle":"Bold", + "horizontalAlignment":"CENTER", + "textColor": [1.0,0.0,1.0,1.0], + "text":"{title_text}" + } + ] + } + ] + } + } +} + diff --git a/packaging/dali-addon.spec b/packaging/dali-addon.spec index 7bb302f..22bfeae 100644 --- a/packaging/dali-addon.spec +++ b/packaging/dali-addon.spec @@ -69,7 +69,7 @@ rm -rf %{buildroot} cd "%{addonBuildDir}" %make_install -cp %{addonDir}/line-mesh.js %{installDir}/line-mesh.js +cp -R %{addonDir}/examples %{installDir}/examples %clean diff --git a/plugins/dali-script-v8/docs/content/constants.js b/plugins/dali-script-v8/docs/content/constants.js index d321285..a09ed33 100644 --- a/plugins/dali-script-v8/docs/content/constants.js +++ b/plugins/dali-script-v8/docs/content/constants.js @@ -184,6 +184,13 @@ Constants accessible under the dali global object. |PROPERTY_ARRAY | integer value | |PROPERTY_MAP | integer value | |PROPERTY_INVALID_INDEX | integer value | +|PROPERTY_READ_ONLY | integer value | +|PROPERTY_READ_WRITE | integer value | +|PROPERTY_ANIMATABLE | integer value | + +|**Item layout type ** | | +|ITEM_LAYOUT_LIST | integer value | +|ITEM_LAYOUT_GRID | integer value | * @class Constants */ diff --git a/plugins/dali-script-v8/docs/content/item-factory.js b/plugins/dali-script-v8/docs/content/item-factory.js new file mode 100644 index 0000000..b7ae5ab --- /dev/null +++ b/plugins/dali-script-v8/docs/content/item-factory.js @@ -0,0 +1,177 @@ +/** + * +## ItemFactory API + + ItemFactory is for storing the data of {{#crossLink "ItemView"}}ItemView{{/crossLink}} + and creating actors for ItemView on request. Each item in ItemView is identified by a + unique ID, and has a linear order from 0. + + A JSON file should be provided to ItemFactory which defines the templates of items + to be used to create the actors. Multiple templates can be defined in the JSON file + for different type of items. + +### Simple example of creating a JSON template for items + +``` + { + "templates": + { + "template-item": + { + "name":"item", + "type":"Actor", + "position":[0,0,0], + "anchorPoint":"TOP_LEFT", + "parentOrigin":"TOP_LEFT", + "actors": + [ + { + "name":"icon", + "type":"ImageView", + "image": + { + "rendererType" : "imageRenderer", + "imageUrl": "{icon_path}" + }, + "position":[20.0, 0.0, 0.0], + "size":[70.0, 70.0, 0.0], + "color":[1.0,1.0,1.0,1.0], + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_LEFT", + "actors": + [ + { + "name":"title", + "anchorPoint":"CENTER_LEFT", + "parentOrigin":"CENTER_RIGHT", + "type":"TextLabel", + "position": [30.0, 0.0, 0.0], + "size":[200.0, 70.0, 0.0], + "pointSize":30, + "fontFamily":"HelveticaNeue", + "fontStyle":"Bold", + "horizontalAlignment":"BEGIN", + "verticalAlignment":"CENTER", + "textColor": [1.0,0.0,1.0,1.0], + "text":"{title_text}" + } + ] + } + ] + } + } + } +``` + + The data of items should be provided to ItemFactory as an array of property maps + in which each map contains the data for each item, including the template to be used + to build the actor and the pairs of key/value to be used to replace the constants + defined in the template. The order of property maps in the array represents the actual + order of items in ItemView. + + ### Example of defining the data of an ItemView with two items + +``` + var itemViewData = [ + { "template" : "template-item", + "icon_path" : "icon0.png", + "title_text" : "Item 0" }, + { "template" : "template-item", + "icon_path" : "icon1.png", + "title_text" : "Item 1" } + ]; +``` + + This means ItemFactory will use the template "template-item" defined in the JSON file + to create the item for ItemView and replace the constants "icon_path" and "title_text" + in the template with their actual values, e.g. "icon0.png" and "Item 0". Each item can + have different template and different data. + + ### Example of creating an ItemFactory with the above JSON template and link it with an ItemView + +![ ](../assets/img/item-view/list.png) + +``` + // Define the data of 100 items + var itemViewData = []; + for (var itemId = 0; itemId < 100; itemId++) + { + var itemData = {}; + itemData["template"] = "template-item"; + itemData["icon_path"] = "icon" + itemId + ".png"; + itemData["title_text"] = "Item " + itemId; + itemViewData[itemId] = itemData; + } + + // Create the item factory and set the JSON template file and item view data + var itemFactory = new dali.ItemFactory(); + itemFactory.jsonTemplateFile = "./item-template.json"; // Set the JSON template file + itemFactory.data = itemViewData; // Set the ItemView data + + // Create the item view with the given item factory + var itemView = new dali.Control("ItemView", itemFactory); + itemView.size = [stageSize.x, stageSize.y, 0.0]; + itemView.parentOrigin = dali.CENTER_LEFT; + itemView.anchorPoint = dali.CENTER_LEFT; + dali.stage.add( itemView ); + + // Add a list layout to ItemView (multiple layouts can be added to the same ItemView) + itemView.addLayout(dali.ITEM_LAYOUT_LIST); + + // Set custom item size for the list layout + // If set, this will overide the predefined item size in the list layout + itemView.setItemSize(0, [350, 100, 0]); // 0 means the first layout added to ItemView + + // Acticate the list layout (which will layout the items as a list) + itemView.activateLayout(0, itemView.size); // 0 means the first layout added to ItemView +``` + + ### Example of changing the data of items in ItemView dynamically + +``` + var data = itemFactory.data; + data[itemId]["icon_path"] = "new-icon.png"; + data[itemId]["title_text"] = "New Item"; + itemFactory.data = data; // ItemView will update the changed items immediately +``` + + @class ItemFactory + +*/ + +/** + * Sets the file name of JSON template that contains the templates for items. + * + * @example + * itemFactory.jsonTemplateFile = "item-template.json"; // ItemFactory will look for the template from this JSON file + * + * @type String + * @property jsonTemplateFile + */ +JSON_TEMPLATE_FILE + +/** + * Sets the data of ItemView + * + * The data is an array of property maps in which each map contains the data + * for each item, including the template to be used to build the actor and + * the pairs of key/value to be used to replace the constants defined in the + * template. The order of property maps in the array represents the actual + * order of items in ItemView. + * + * @example + * var itemViewData = [ + * { "template" : "template-item", + * "icon_path" : "icon0.png", + * "title_text" : "Item 0" }, + * { "template" : "template-item", + * "icon_path" : "icon1.png", + * "title_text" : "Item 1" } + * ]; + * + * itemFactory.data = itemViewData; // ItemFactory will look for the template from this JSON file + * + * @type Array + * @property data + */ +DATA diff --git a/plugins/dali-script-v8/docs/content/item-view.js b/plugins/dali-script-v8/docs/content/item-view.js new file mode 100644 index 0000000..776c5ea --- /dev/null +++ b/plugins/dali-script-v8/docs/content/item-view.js @@ -0,0 +1,62 @@ +/** + * +## ItemView API + + ItemView is a scrollable layout container with built-in layouts to determine + the logical position of each item in a layout. + + Actors are provided from an external {{#crossLink "ItemFactory"}}ItemFactory{{/crossLink}}, + to display the currently visible items. ItemFactory is for storing the data of ItemView and + creating actors for ItemView on request. Each item in ItemView is identified by a unique ID, + and has a linear order from 0. + + ### Example of creating an ItemView (see {{#crossLink "ItemFactory"}}ItemFactory{{/crossLink}} API for a full example) + +``` + // Define the data of 100 items + var itemViewData = []; + for (var itemId = 0; itemId < 100; itemId++) + { + var itemData = {}; + itemData["template"] = "template-item"; + itemData["title_text"] = "Item " + itemId; + itemViewData[itemId] = itemData; + } + + // Create an item factory and set the JSON template file and item view data + var itemFactory = new dali.ItemFactory(); + itemFactory.jsonTemplateFile = "./item-template.json"; // Set the JSON template file + itemFactory.data = itemViewData; // Set the ItemView data + + // Create the item view with the given item factory + var itemView = new dali.Control("ItemView", itemFactory); + itemView.size = [stageSize.x, stageSize.y, 0.0]; + itemView.parentOrigin = dali.CENTER_LEFT; + itemView.anchorPoint = dali.CENTER_LEFT; + dali.stage.add( itemView ); + + // Add a scroll bar to ItemView (optional) + var scrollBar = new dali.Control("ScrollBar"); + scrollBar.parentOrigin = dali.TOP_RIGHT; + scrollBar.anchorPoint = dali.TOP_RIGHT; + scrollBar.widthResizePolicy = "FIT_TO_CHILDREN"; + scrollBar.heightResizePolicy = "FILL_TO_PARENT"; + scrollBar.indicatorHeightPolicy = "Fixed"; + scrollBar.indicatorFixedHeight = 60.0; + itemView.add(scrollBar); + + // Add a list layout to ItemView (multiple layouts can be added to the same ItemView) + itemView.addLayout(dali.ITEM_LAYOUT_LIST); + + // Set custom item size for the list layout + // If set, this will overide the predefined item size in the list layout + itemView.setItemSize(0, [350, 100, 0]); // 0 means the first layout added to ItemView + + // Acticate the list layout (which will layout the items as a list) + itemView.activateLayout(0, itemView.size); // 0 means the first layout added to ItemView +``` + + @class ItemView + @extends Actor + +*/ diff --git a/plugins/dali-script-v8/file.list b/plugins/dali-script-v8/file.list index e50d5cd..598d90e 100644 --- a/plugins/dali-script-v8/file.list +++ b/plugins/dali-script-v8/file.list @@ -13,6 +13,9 @@ script_v8_plugin_src_files = \ $(v8_plugin_dir)/actors/actor-api.cpp \ $(v8_plugin_dir)/actors/layer-api.cpp \ $(v8_plugin_dir)/actors/camera-actor-api.cpp \ + $(v8_plugin_dir)/controls/control-wrapper.cpp \ + $(v8_plugin_dir)/controls/item-factory-wrapper.cpp \ + $(v8_plugin_dir)/controls/item-view-api.cpp \ $(v8_plugin_dir)/constants/constants-wrapper.cpp \ $(v8_plugin_dir)/animation/animation-api.cpp \ $(v8_plugin_dir)/animation/animation-wrapper.cpp \ diff --git a/plugins/dali-script-v8/src/actors/actor-api.cpp b/plugins/dali-script-v8/src/actors/actor-api.cpp index 5bac818..371639d 100644 --- a/plugins/dali-script-v8/src/actors/actor-api.cpp +++ b/plugins/dali-script-v8/src/actors/actor-api.cpp @@ -36,21 +36,14 @@ namespace V8Plugin namespace // unanmed namespace { + Actor GetActor( v8::Isolate* isolate, const v8::FunctionCallbackInfo& args ) { HandleWrapper* handleWrapper = HandleWrapper::Unwrap( isolate, args.This() ); return Actor::DownCast( handleWrapper->mHandle ); } -} //unanmed namespace - -namespace TextLabelApi -{ - Actor New( const v8::FunctionCallbackInfo< v8::Value >& args ) - { - return Dali::Toolkit::TextLabel::New(); - } -} +} //unanmed namespace /*************************************** * ACTOR API FUNCTIONS @@ -279,7 +272,7 @@ void ActorApi::GetChildCount( const v8::FunctionCallbackInfo& args ) } /** - * Retrieve and child actor by index. + * Retrieve a child actor by index. * * @for Actor * @method getChildAt diff --git a/plugins/dali-script-v8/src/actors/actor-api.h b/plugins/dali-script-v8/src/actors/actor-api.h index 26f8991..bcd600e 100644 --- a/plugins/dali-script-v8/src/actors/actor-api.h +++ b/plugins/dali-script-v8/src/actors/actor-api.h @@ -28,14 +28,6 @@ namespace Dali namespace V8Plugin { -namespace TextLabelApi -{ - /** - * Temporary TextView constructor - */ - Actor New( const v8::FunctionCallbackInfo< v8::Value >& args ); -} - namespace ActorApi { diff --git a/plugins/dali-script-v8/src/actors/actor-wrapper.cpp b/plugins/dali-script-v8/src/actors/actor-wrapper.cpp index 336ed23..a1c0f78 100644 --- a/plugins/dali-script-v8/src/actors/actor-wrapper.cpp +++ b/plugins/dali-script-v8/src/actors/actor-wrapper.cpp @@ -84,7 +84,7 @@ struct ActorApiStruct /** * Lookup table to match a actor type with a constructor and supported API's. - * HandleWrapper::ActorType is used to index this table + * ActorWrapper::ActorType is used to index this table */ const ActorApiStruct ActorApiLookup[]= { @@ -305,7 +305,7 @@ v8::Handle ActorWrapper::WrapActor( v8::Isolate* isolate, Actor acto // create an instance of the template v8::Local localObject = objectTemplate->NewInstance(); - // create teh actor object + // create the actor object ActorWrapper* pointer = new ActorWrapper( actor, Dali::V8Plugin::DaliWrapper::Get().GetDaliGarbageCollector() ); // assign the JavaScript object to the wrapper. @@ -392,42 +392,6 @@ void ActorWrapper::NewActor( const v8::FunctionCallbackInfo< v8::Value >& args) args.GetReturnValue().Set( localObject ); } -void ActorWrapper::NewControl( const v8::FunctionCallbackInfo< v8::Value >& args) -{ - v8::Isolate* isolate = args.GetIsolate(); - v8::HandleScope handleScope( isolate ); - - if( !args.IsConstructCall() ) - { - DALI_SCRIPT_EXCEPTION( isolate, "constructor called without 'new" ); - return; - } - - bool found( false ); - std::string controlName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args ); - - if( !found ) - { - DALI_SCRIPT_EXCEPTION( isolate, "missing control name" ); - return; - } - Actor control; - Dali::TypeInfo typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( controlName ); - if( typeInfo ) // handle, check if it has a value - { - Dali::BaseHandle handle = typeInfo.CreateInstance(); - if( handle ) - { - control = Actor::DownCast( handle ); - } - } - - v8::Local localObject = WrapActor( isolate, control, ACTOR ); - - args.GetReturnValue().Set( localObject ); -} - - /** * given an actor type name, e.g. CameraActor returns the type, e.g. ActorWrapper::CAMERA_ACTOR */ @@ -443,8 +407,6 @@ ActorWrapper::ActorType ActorWrapper::GetActorType( const std::string& name ) return ActorWrapper::UNKNOWN_ACTOR; } - - } // namespace V8Plugin } // namespace Dali diff --git a/plugins/dali-script-v8/src/actors/actor-wrapper.h b/plugins/dali-script-v8/src/actors/actor-wrapper.h index fd12185..e84559f 100644 --- a/plugins/dali-script-v8/src/actors/actor-wrapper.h +++ b/plugins/dali-script-v8/src/actors/actor-wrapper.h @@ -76,13 +76,6 @@ public: static void NewActor( const v8::FunctionCallbackInfo< v8::Value >& args); /** - * @brief Creates a new Control wrapped inside a Javascript Object. - * @note: the control type is passed as a parameter e.g. 'TextField' - * @param[in] args v8 function call arguments interpreted - */ - static void NewControl( const v8::FunctionCallbackInfo< v8::Value >& args); - - /** * @brief Wraps an actor of a given type */ static v8::Handle WrapActor(v8::Isolate* isolate, Dali::Actor actor,ActorType actorType); @@ -107,14 +100,16 @@ public: */ static ActorWrapper::ActorType GetActorType( const std::string& name ); -private: +protected: /** - * Helper to make the actor template + * @brief Helper to make the actor template * */ static v8::Handle MakeDaliActorTemplate( v8::Isolate* isolate, ActorType actorType ); +private: + /** * Helper, get an actor template given an actor type */ diff --git a/plugins/dali-script-v8/src/constants/constants-wrapper.cpp b/plugins/dali-script-v8/src/constants/constants-wrapper.cpp index acaacb6..edbd62b 100644 --- a/plugins/dali-script-v8/src/constants/constants-wrapper.cpp +++ b/plugins/dali-script-v8/src/constants/constants-wrapper.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace Dali { @@ -243,6 +244,12 @@ const IntegerPair EnumTable[] = { "PROPERTY_ARRAY", Property::ARRAY }, { "PROPERTY_MAP", Property::MAP }, { "PROPERTY_INVALID_INDEX", Property::INVALID_INDEX }, + { "PROPERTY_READ_ONLY", Property::READ_ONLY }, + { "PROPERTY_READ_WRITE", Property::READ_WRITE }, + { "PROPERTY_ANIMATABLE", Property::ANIMATABLE }, + + { "ITEM_LAYOUT_LIST", Toolkit::DefaultItemLayout::LIST }, + { "ITEM_LAYOUT_GRID", Toolkit::DefaultItemLayout::GRID }, }; const unsigned int EnumTableCount = sizeof(EnumTable)/sizeof(EnumTable[0]); diff --git a/plugins/dali-script-v8/src/controls/control-wrapper.cpp b/plugins/dali-script-v8/src/controls/control-wrapper.cpp new file mode 100644 index 0000000..09093a2 --- /dev/null +++ b/plugins/dali-script-v8/src/controls/control-wrapper.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include +#include "control-wrapper.h" + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace V8Plugin +{ + +v8::Persistent ControlWrapper::mControlTemplate; +v8::Persistent ControlWrapper::mItemViewTemplate; + +Vector< void* > ControlWrapper::mControlGarbageContainer; + +namespace +{ + + +/** + * pointer to a persistent template handle + */ +struct ControlTemplate +{ + v8::Persistent* controlTemplate; +}; + +/** + * array of templates for each type of control + */ +const ControlTemplate ControlTemplateLookup[]= +{ + { &ControlWrapper::mControlTemplate }, // CONTROL + { &ControlWrapper::mItemViewTemplate } // ITEMVIEW +}; + +/** + * Bitmask of API's that an control can support + */ +enum ControlApiBitMask +{ + CONTROL_API = 1 << 0, + ITEMVIEW_API = 1 << 1 +}; + +/** + * structure used for the ControlApiLookup. + */ +struct ControlApiStruct +{ + const char* controlName; + ControlWrapper::ControlType controlType; + Toolkit::Control (*constructor)( const v8::FunctionCallbackInfo< v8::Value >& args); + int supportApis; +}; + +/** + * Lookup table to match a control type with a constructor and supported API's. + * ControlWrapper::ControlType is used to index this table + */ +const ControlApiStruct ControlApiLookup[]= +{ + {"Control", ControlWrapper::CONTROL, NULL, CONTROL_API }, + {"ItemView", ControlWrapper::ITEMVIEW, ItemViewApi::New, CONTROL_API | ITEMVIEW_API }, +}; + +const unsigned int ControlApiLookupCount = sizeof(ControlApiLookup)/sizeof(ControlApiLookup[0]); + + +/** + * Creates a control given a type name + * Uses the type registry to create an control of the correct type + */ +Toolkit::Control CreateControl( const v8::FunctionCallbackInfo< v8::Value >& args, + const std::string& typeName ) +{ + Toolkit::Control control; + + ControlWrapper::ControlType controlType = ControlWrapper::GetControlType( typeName ); + + // if we don't currently have specific binding for the given control type, + // try to use type registry to create it + if( controlType == ControlWrapper::UNKNOWN_CONTROL ) + { + Dali::TypeInfo typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( typeName ); + if( typeInfo ) + { + Dali::BaseHandle handle = typeInfo.CreateInstance(); + if( handle ) + { + control = Toolkit::Control::DownCast( handle ); + if( !control ) + { + DALI_SCRIPT_EXCEPTION( args.GetIsolate(), "Unknown control type" ); + return Toolkit::Control(); + } + } + } + } + else + { + // run the constructor for this type of control so it can pull out custom parameters + control = (ControlApiLookup[controlType].constructor)( args ); + } + + return control; +} + +/** + * given a control type return what api's it supports + */ +int GetControlSupportedApis( ControlWrapper::ControlType type ) +{ + return ControlApiLookup[type].supportApis; +} + +/** + * Used for the ControlFunctionTable to map function names to functions + * with for a specific API + */ +struct ControlFunctions +{ + const char* name; ///< function name + void (*function)( const v8::FunctionCallbackInfo< v8::Value >& args); + ControlApiBitMask api; +}; + +/** + * Contains a list of all functions that can be called in + * ItemView + */ +const ControlFunctions ControlFunctionTable[]= +{ + + /************************************** + * ItemView API + **************************************/ + { "GetLayoutCount", ItemViewApi::GetLayoutCount, ITEMVIEW_API }, + { "AddLayout", ItemViewApi::AddLayout, ITEMVIEW_API }, + { "RemoveLayout", ItemViewApi::RemoveLayout, ITEMVIEW_API }, + { "ActivateLayout", ItemViewApi::ActivateLayout, ITEMVIEW_API }, + { "GetItemSize", ItemViewApi::GetItemSize, ITEMVIEW_API }, + { "SetItemSize", ItemViewApi::SetItemSize, ITEMVIEW_API }, + { "ScrollToItem", ItemViewApi::ScrollToItem, ITEMVIEW_API }, + { "GetItem", ItemViewApi::GetItem, ITEMVIEW_API }, + { "GetItemId", ItemViewApi::GetItemId, ITEMVIEW_API }, + { "GetItemsRange", ItemViewApi::GetItemsRange, ITEMVIEW_API }, + +}; + +const unsigned int ControlFunctionTableCount = sizeof(ControlFunctionTable)/sizeof(ControlFunctionTable[0]); +} //un-named space + + +ControlWrapper::ControlWrapper( Toolkit::Control control, + GarbageCollectorInterface& gc ) +: ActorWrapper( control, gc ), + mControl( control ) + +{ +} + +ControlWrapper::~ControlWrapper() +{ + mControlGarbageContainer.Release(); +} + +v8::Handle ControlWrapper::WrapControl(v8::Isolate* isolate, Toolkit::Control control ) +{ + v8::EscapableHandleScope handleScope( isolate ); + + // Check whether the control is a Control + ControlWrapper::ControlType controlType = GetControlType( control.GetTypeName() ); + + if( controlType == ControlWrapper::UNKNOWN_CONTROL && Toolkit::Control::DownCast(control) ) + { + controlType = ControlWrapper::CONTROL; + } + + v8::Local object = WrapControl( isolate, control, controlType ); + + return handleScope.Escape( object ); +} + +Toolkit::Control ControlWrapper::GetControl() +{ + return mControl; +} + +v8::Handle ControlWrapper::WrapControl( v8::Isolate* isolate, Toolkit::Control control, ControlType controlType ) +{ + v8::EscapableHandleScope handleScope( isolate ); + v8::Local objectTemplate; + + objectTemplate = GetControlTemplate( isolate, controlType ); + + // create an instance of the template + v8::Local localObject = objectTemplate->NewInstance(); + + // create the control object + ControlWrapper* pointer = new ControlWrapper( control, Dali::V8Plugin::DaliWrapper::Get().GetDaliGarbageCollector() ); + + // assign the JavaScript object to the wrapper. + // This also stores Dali object, in an internal field inside the JavaScript object. + pointer->SetJavascriptObject( isolate, localObject ); + + return handleScope.Escape( localObject ); +} + +v8::Local ControlWrapper::GetControlTemplate( v8::Isolate* isolate, ControlWrapper::ControlType type ) +{ + v8::EscapableHandleScope handleScope( isolate ); + v8::Local objectTemplate; + + if( ControlTemplateLookup[type].controlTemplate->IsEmpty() ) + { + objectTemplate = MakeDaliControlTemplate( isolate, type ); + ControlTemplateLookup[type].controlTemplate->Reset( isolate, objectTemplate ); + } + else + { + // get the object template + objectTemplate = v8::Local::New( isolate, *ControlTemplateLookup[type].controlTemplate ); + } + + return handleScope.Escape( objectTemplate ); +} + +v8::Handle ControlWrapper::MakeDaliControlTemplate( v8::Isolate* isolate, ControlType controlType ) +{ + v8::EscapableHandleScope handleScope( isolate ); + + // all the controls support actor APIs + v8::Local objTemplate = ActorWrapper::MakeDaliActorTemplate( isolate, ActorWrapper::ACTOR ); + + // find out what API's this control supports + int supportApis = GetControlSupportedApis( controlType ); + + // add our function properties + for( unsigned int i = 0; i < ControlFunctionTableCount; ++i ) + { + const ControlFunctions property = ControlFunctionTable[i]; + + // check to see if the control supports a certain type of API + // e.g. ItemView will support CONTROL_API and ITEMVIEW_API + if( supportApis & property.api ) + { + std::string funcName = V8Utils::GetJavaScriptFunctionName( property.name); + + objTemplate->Set( v8::String::NewFromUtf8( isolate, funcName.c_str() ), + v8::FunctionTemplate::New( isolate, property.function ) ); + } + } + + return handleScope.Escape( objTemplate ); +} + +void ControlWrapper::NewControl( const v8::FunctionCallbackInfo< v8::Value >& args) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + if( !args.IsConstructCall() ) + { + DALI_SCRIPT_EXCEPTION( isolate, "constructor called without 'new" ); + return; + } + + bool found( false ); + std::string controlName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args ); + + Toolkit::Control control; + if( found && controlName != ControlApiLookup[0].controlName ) + { + control = CreateControl( args, controlName ); // create the control with the given type + } + else + { + control = Toolkit::Control::New(); // no given type, so create the base type of control + } + + if( control ) + { + v8::Local localObject = WrapControl( isolate, control ); + args.GetReturnValue().Set( localObject ); + } + else + { + DALI_SCRIPT_EXCEPTION( isolate, "unsupported control type" ); + } +} + +/** + * Given a control type name, e.g. ItemView returns the type, e.g. ControlWrapper::ITEMVIEW + */ +ControlWrapper::ControlType ControlWrapper::GetControlType( const std::string& name ) +{ + for( unsigned int i = 0 ; i < ControlApiLookupCount ; i++ ) + { + if( ControlApiLookup[i].controlName == name ) + { + return ControlApiLookup[i].controlType; + } + } + return ControlWrapper::UNKNOWN_CONTROL; +} + +void ControlWrapper::RegisterGarbage(void* garbage) +{ + mControlGarbageContainer.PushBack(garbage); +} + +} // namespace V8Plugin + +} // namespace Dali diff --git a/plugins/dali-script-v8/src/controls/control-wrapper.h b/plugins/dali-script-v8/src/controls/control-wrapper.h new file mode 100644 index 0000000..dc4b636 --- /dev/null +++ b/plugins/dali-script-v8/src/controls/control-wrapper.h @@ -0,0 +1,127 @@ +#ifndef __DALI_V8PLUGIN_CONTROL_WRAPPER_H__ +#define __DALI_V8PLUGIN_CONTROL_WRAPPER_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace V8Plugin +{ + + +/** + * Wraps a Dali Control. + */ +class ControlWrapper : public ActorWrapper +{ + +public: + + /** + * Control type used an index. + * These enums are used to index the ControlApiLookup table in control-wrapper.cpp. + * Any changes made must be reflected in the ControlApiLookup otherwise it may segfault when creating a control + */ + enum ControlType + { + UNKNOWN_CONTROL = -1, + CONTROL = 0, + ITEMVIEW = 1 + }; + + /** + * Constructor + * @param control DALi control + * @param gc garbage collection interface + */ + ControlWrapper( Toolkit::Control control, + GarbageCollectorInterface& gc ); + + /** + * destructor + */ + virtual ~ControlWrapper(); + + /** + * @brief Creates a new Control wrapped inside a Javascript Object. + * @note: the control type is passed as a parameter e.g. 'ItemView' + * @param[in] args v8 function call arguments interpreted + */ + static void NewControl( const v8::FunctionCallbackInfo< v8::Value >& args); + + /** + * @brief Wraps a control of a given type + */ + static v8::Handle WrapControl(v8::Isolate* isolate, Toolkit::Control control, ControlType controlType); + + /** + * @brief Wraps a control, the type is looked up from the control + */ + static v8::Handle WrapControl(v8::Isolate* isolate, Toolkit::Control control ); + + // The Control ObjectTemplates. + static v8::Persistent mControlTemplate; + static v8::Persistent mItemViewTemplate; + static v8::Persistent mScrollViewTemplate; + + /** + * @return the wrapped control + */ + Toolkit::Control GetControl(); + + /** + * @return the control type + */ + static ControlWrapper::ControlType GetControlType( const std::string& name ); + + /** + * @brief Register the garbage to be released when the wrapped control is deleted. + */ + static void RegisterGarbage(void* garbage); + +private: + + /** + * Helper to make the control template + */ + static v8::Handle MakeDaliControlTemplate( v8::Isolate* isolate, ControlType controlType ); + + /** + * Helper, get a control template given a control type + */ + static v8::Local GetControlTemplate( v8::Isolate* isolate, ControlType type ); + + Toolkit::Control mControl; + static Vector< void* > mControlGarbageContainer; + +}; + +} // namespace V8Plugin + +} // namespace Dali + +#endif // header diff --git a/plugins/dali-script-v8/src/controls/item-factory-wrapper.cpp b/plugins/dali-script-v8/src/controls/item-factory-wrapper.cpp new file mode 100644 index 0000000..62535cb --- /dev/null +++ b/plugins/dali-script-v8/src/controls/item-factory-wrapper.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "item-factory-wrapper.h" + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include + +namespace Dali +{ + +namespace V8Plugin +{ + +v8::Persistent ItemFactoryWrapper::mItemFactoryTemplate; + +namespace +{ + +typedef std::vector< Property::Map > ItemDataContainer; + +// Implementation of ItemFactory for providing actors to ItemView +class ItemFactory : public Toolkit::ItemFactory +{ +public: + + /** + * Constructor + * @param application class, stored as reference + */ + ItemFactory() + : mJsonFileLoaded(false), + mNumberOfItems(0) + { + mBuilder = Toolkit::Builder::New(); + } + + /** + * Set the name of the JSON file which defines the templates of items. + * @param jsonFile The JSON file + */ + void SetJsonTemplateFile(std::string jsonFile) + { + if(mJsonFile != jsonFile) + { + mJsonFile = jsonFile; + LoadJsonFile(mJsonFile); + + // Check whether any layout activated in ItemView + Toolkit::ItemView itemView = mItemView.GetHandle(); + if(itemView && itemView.GetActiveLayout() != NULL) + { + // Refresh ItemView if item templates are changed + itemView.Refresh(); + } + } + } + + /** + * Returns the name of the JSON file. + * @return The JSON file name + */ + std::string GetJsonTemplate() + { + return mJsonFile; + } + + /** + * Set the data to be used to create new items. + * + * If ItemView is already created, this will immediately update ItemView with the + * new data. + * + * The data is an array of property maps in which each map contains the data for + * each item, including the template to be used to build the actor and the pairs + * of key/value to be used to replace the constants defined in the template. + * The order of property maps in the array represents the actual order of items + * in ItemView. + * + * @param data The array of property maps + */ + void SetData(ItemDataContainer data) + { + ItemDataContainer currentData = mData; + mData = data; + mNumberOfItems = mData.size(); + + // Check whether any layout activated in ItemView + Toolkit::ItemView itemView = mItemView.GetHandle(); + if(itemView && itemView.GetActiveLayout() != NULL) + { + unsigned int currentNumberOfItems = currentData.size(); + unsigned int newNumberOfItems = data.size(); + + // Check whether any items added or deleted from the data + // which requires ItemView to be refreshed with the new data + if(currentNumberOfItems != newNumberOfItems) + { + itemView.Refresh(); + } + else + { + for( unsigned int itemId = 0; itemId < newNumberOfItems; itemId++) + { + // Check whether the item is already built in ItemView + Actor itemActor = itemView.GetItem(itemId); + if(itemActor) + { + // Check if the item needs to be rebuilt + if( !V8Utils::IsPropertyMapIdentical(currentData[itemId], data[itemId]) ) + { + // Rebuild the item with the new data + Actor newItemActor = NewItem(itemId); + + // Replace the old item with the new one + itemView.ReplaceItem( Toolkit::Item( itemId, newItemActor ), 0.0f ); + } + } + } + } + } + } + + /** + * Retrieve the data. + * @return the data. + */ + ItemDataContainer GetData() + { + return mData; + } + + /** + * Store a weak handle of ItemView in order to access ItemView APIs + * from this ItemFactory implementation + * @return the data. + */ + void SetItemView(Toolkit::ItemView itemView) + { + mItemView = itemView; + } + +public: // From Toolkit::ItemFactory + + /** + * Query the number of items available from the factory. + * The maximum available item has an ID of GetNumberOfItems() - 1. + */ + virtual unsigned int GetNumberOfItems() + { + return mJsonFileLoaded ? mNumberOfItems : 0; + } + + /** + * Create an Actor to represent a visible item. + * @param itemId + * @return the created actor. + */ + virtual Actor NewItem(unsigned int itemId) + { + std::string itemTemplate; + + Property::Map constantsMap = mData[itemId]; + for ( unsigned int i = 0, count = constantsMap.Count(); i < count; ++i ) + { + Property::Value& constantValue = constantsMap.GetValue(i); + if(constantsMap.GetKey(i) == "template") + { + constantValue.Get(itemTemplate); + } + else + { + mBuilder.AddConstant( constantsMap.GetKey(i), constantValue ); + } + } + + Actor item = Actor::DownCast( mBuilder.Create(itemTemplate) ); + return item; + } + +private: + + /** + * Load the JSON file. + * @param The JSON file name + */ + void LoadJsonFile(std::string jsonFile) + { + try + { + std::string data; + V8Utils::GetFileContents(jsonFile, data); + + mBuilder.LoadFromString(data); + + mJsonFileLoaded = true; + } + catch(...) + { +// printf("invalid JSON data\n"); + mJsonFileLoaded = false; + } + } + +private: + + std::string mJsonFile; + bool mJsonFileLoaded; + Toolkit::Builder mBuilder; + unsigned int mNumberOfItems; + ItemDataContainer mData; + WeakHandle< Toolkit::ItemView > mItemView; +}; + +} //un-named space + +ItemFactoryWrapper::ItemFactoryWrapper( Toolkit::ItemFactory& factory, GarbageCollectorInterface& gc ) +: BaseWrappedObject( BaseWrappedObject::ITEMFACTORY , gc ), + mItemFactory( factory ) +{ +} + +ItemFactoryWrapper::~ItemFactoryWrapper() +{ +} + +v8::Handle ItemFactoryWrapper::WrapItemFactory(v8::Isolate* isolate, Toolkit::ItemFactory& factory ) +{ + v8::EscapableHandleScope handleScope( isolate ); + v8::Local objectTemplate; + + objectTemplate = GetItemFactoryTemplate( isolate ); + + // create an instance of the template + v8::Local localObject = objectTemplate->NewInstance(); + + // create the ItemFactory wrapper + ItemFactoryWrapper* pointer = new ItemFactoryWrapper( factory, Dali::V8Plugin::DaliWrapper::Get().GetDaliGarbageCollector() ); + + // assign the JavaScript object to the wrapper. + pointer->SetJavascriptObject( isolate, localObject ); + + return handleScope.Escape( localObject ); +} + +v8::Local ItemFactoryWrapper::GetItemFactoryTemplate( v8::Isolate* isolate) +{ + v8::EscapableHandleScope handleScope( isolate ); + v8::Local objectTemplate; + + if( mItemFactoryTemplate.IsEmpty() ) + { + objectTemplate = MakeItemFactoryTemplate( isolate ); + mItemFactoryTemplate.Reset( isolate, objectTemplate ); + } + else + { + // get the object template + objectTemplate = v8::Local::New( isolate, mItemFactoryTemplate ); + } + return handleScope.Escape( objectTemplate ); +} + +v8::Handle ItemFactoryWrapper::MakeItemFactoryTemplate( v8::Isolate* isolate ) +{ + v8::EscapableHandleScope handleScope( isolate ); + + v8::Local objTemplate = v8::ObjectTemplate::New(); + + objTemplate->SetInternalFieldCount( BaseWrappedObject::FIELD_COUNT ); + + // set property setter and getter + objTemplate->SetNamedPropertyHandler( ItemFactoryWrapper::PropertyGet, ItemFactoryWrapper::PropertySet); + + return handleScope.Escape( objTemplate ); +} + +void ItemFactoryWrapper::NewItemFactory( const v8::FunctionCallbackInfo< v8::Value >& args) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate); + + if( !args.IsConstructCall() ) + { + DALI_SCRIPT_EXCEPTION( isolate, "ItemFactory constructor called without 'new'" ); + return; + } + + Toolkit::ItemFactory* factory = new ItemFactory(); + + v8::Local localObject = WrapItemFactory( isolate, *factory ); + args.GetReturnValue().Set( localObject ); +} + +Toolkit::ItemFactory& ItemFactoryWrapper::GetItemFactoryFromParams( int paramIndex, + bool& found, + v8::Isolate* isolate, + const v8::FunctionCallbackInfo< v8::Value >& args ) +{ + found = false; + + v8::HandleScope handleScope( isolate ); + BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( paramIndex, BaseWrappedObject::ITEMFACTORY, isolate, args ); + if( wrappedObject ) + { + found = true; + ItemFactoryWrapper* wrapper = static_cast< ItemFactoryWrapper *>(wrappedObject); + return wrapper->GetItemFactory(); + } + else + { + DALI_SCRIPT_EXCEPTION( isolate, "no valid ItemFactory parameter" ); + Toolkit::ItemFactory* dummyFactory = new ItemFactory(); + return *dummyFactory; // avoid build error + } +} + +ItemFactoryWrapper* ItemFactoryWrapper::Unwrap( v8::Isolate* isolate, v8::Handle< v8::Object> obj) +{ + v8::HandleScope handleScope( isolate ); + + v8::Local field = v8::Local::Cast( obj->GetInternalField(0) ); + void* ptr = field->Value(); + return static_cast< ItemFactoryWrapper *>(ptr); +} + +void ItemFactoryWrapper::PropertyGet( v8::Local propertyName, + const v8::PropertyCallbackInfo& info) +{ + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + // get the property name + std::string name = V8Utils::v8StringToStdString( propertyName ); + + if( std::isupper( name[0] )) + { + return; + } + + // unwrap the object + ItemFactoryWrapper* itemFactoryWrapper = Unwrap( isolate, info.This() ); + if( !itemFactoryWrapper ) + { + return; + } + + ItemFactory& factory = static_cast( itemFactoryWrapper->GetItemFactory() ); + + if( name == "jsonTemplateFile" ) + { + std::string jsonTemplateFile = factory.GetJsonTemplate(); + info.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, jsonTemplateFile.c_str())); + } + else if( name == "data" ) + { + ItemDataContainer data = factory.GetData(); + unsigned int itemCount = data.size(); + + v8::Local array= v8::Array::New( isolate, itemCount ); + for( unsigned int i = 0; i < itemCount; i++) + { + v8::Local mapObject = v8::Object::New( isolate ); + V8Utils::CreatePropertyMap( isolate, data[i], mapObject ); + + array->Set( i, mapObject); + } + + info.GetReturnValue().Set(array); + } + else + { + std::string error="Invalid property Get for "+name + "\n"; + DALI_SCRIPT_EXCEPTION( isolate, error ); + } +} + +void ItemFactoryWrapper::PropertySet( v8::Local propertyName, + v8::Local javaScriptValue, + const v8::PropertyCallbackInfo& info) +{ + + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + // get the property name + std::string name = V8Utils::v8StringToStdString( propertyName ); + + // unwrap the object + ItemFactoryWrapper* itemFactoryWrapper = Unwrap( isolate, info.This() ); + if( !itemFactoryWrapper ) + { + return; + } + + ItemFactory& factory = static_cast( itemFactoryWrapper->GetItemFactory() ); + + if( name == "jsonTemplateFile" && javaScriptValue->IsString() ) + { + std::string jsonTemplateFile = V8Utils::v8StringToStdString( javaScriptValue ); + factory.SetJsonTemplateFile(jsonTemplateFile); + } + else if( name == "data" && javaScriptValue->IsArray() ) + { + v8::Local array = v8::Local::Cast(javaScriptValue); + + ItemDataContainer data; + + for( unsigned int i = 0; i < array->Length(); ++i ) + { + v8::Local itemData = array->Get(i); + + if( itemData->IsObject() ) + { + Dali::Property::Map map = V8Utils::GetPropertyMapFromObject( isolate, itemData->ToObject() ); + data.push_back(map); + } + } + + factory.SetData(data); + } + else + { + std::string error = "Invalid property Set for " + name + "\n"; + DALI_SCRIPT_EXCEPTION( isolate, error ); + } +} + +Toolkit::ItemFactory& ItemFactoryWrapper::GetItemFactory() +{ + return mItemFactory; +} + +void ItemFactoryWrapper::SetItemView(Toolkit::ItemFactory& itemFactory, Toolkit::ItemView itemView) +{ + ItemFactory& factory = static_cast( itemFactory ); + factory.SetItemView(itemView); +} + +} // namespace V8Plugin + +} // namespace Dali diff --git a/plugins/dali-script-v8/src/controls/item-factory-wrapper.h b/plugins/dali-script-v8/src/controls/item-factory-wrapper.h new file mode 100644 index 0000000..cfb21fb --- /dev/null +++ b/plugins/dali-script-v8/src/controls/item-factory-wrapper.h @@ -0,0 +1,146 @@ +#ifndef __DALI_V8PLUGIN_ITEM_FACTORY_WRAPPER_H__ +#define __DALI_V8PLUGIN_ITEM_FACTORY_WRAPPER_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace V8Plugin +{ + + +/** + * Wraps a Dali ItemFactory. + */ +class ItemFactoryWrapper : public BaseWrappedObject +{ + +public: + + /** + * Constructor + * @param factory DALi ItemFactory + * @param gc garbage collection interface + */ + ItemFactoryWrapper( Toolkit::ItemFactory& factory, + GarbageCollectorInterface& gc ); + + /** + * destructor + */ + virtual ~ItemFactoryWrapper(); + + /** + * @brief Creates a new ItemFactory wrapped inside a Javascript Object. + * @note: the item template and data are passed as a parameter e.g. 'template' + * @param[in] args v8 function call arguments interpreted + */ + static void NewItemFactory( const v8::FunctionCallbackInfo< v8::Value >& args); + + /** + * @brief Wraps an ItemFactory + */ + static v8::Handle WrapItemFactory(v8::Isolate* isolate, Toolkit::ItemFactory& factory ); + + // The ItemFactory ObjectTemplates. + static v8::Persistent mItemFactoryTemplate; + + /** + * @brief Helper to get ItemFactory from the JavaScript object held in the given function argument + * @param[in] paramIndex Argument index the object is held in + * @param[in] found Whether ItemFactory is found in the given function parameter + * @param[in] isolate v8 isolated instance + * @param[in] args v8 function call arguments interpreted + */ + static Toolkit::ItemFactory& GetItemFactoryFromParams( int paramIndex, + bool& found, + v8::Isolate* isolate, + const v8::FunctionCallbackInfo< v8::Value >& args ); + + /** + * @brief Helper to store a weak handle of ItemView in the given ItemFactory + * @param[in] itemFactory The item factory used to provide items to the given item view + * @param[in] itemView The ItemView which uses the given item factory to create items + */ + static void SetItemView(Toolkit::ItemFactory& itemFactory, Toolkit::ItemView itemView); + + /** + * @return the wrapped item factory + */ + Toolkit::ItemFactory& GetItemFactory(); + +private: + + /** + * Helper to make the item factory template + */ + static v8::Handle MakeItemFactoryTemplate( v8::Isolate* isolate ); + + /** + * Helper, get a item factory template + */ + static v8::Local GetItemFactoryTemplate( v8::Isolate* isolate ); + + /** + * @brief get the value for a property for JavaScript object than contains a Dali ItemFactory. + * E.g. Get( "data", JavaScript object that wraps a Dali ItemFactory ) + * @param[in] propertyName property name + * @param[in] info reference to PropertyCallbackInfo structure (contains the Javascript + * object and the return value). + */ + static void PropertyGet( v8::Local propertyName, + const v8::PropertyCallbackInfo& info); + + /** + * @brief Set the value for a property for JavaScript object than contains a Dali ItemFactory. + * E.g. Set( "data", itemData, JavaScript object that wraps a Dali ItemFactory) + * @param[in] propertyName property name + * @param[in] javaScriptValue javascript value to set, this is typically a number + * @param[in] info reference to PropertyCallbackInfo structure (contains the Javascript + * object). + */ + static void PropertySet( v8::Local propertyName, + v8::Local javaScriptValue, + const v8::PropertyCallbackInfo& info); + + + /** + * @brief Extract a item factory wrapper from a javascript object + * @return item factory wrapper + */ + static ItemFactoryWrapper* Unwrap( v8::Isolate* isolate, v8::Handle< v8::Object> obj); + + Toolkit::ItemFactory& mItemFactory; + +}; + +} // namespace V8Plugin + +} // namespace Dali + +#endif // header diff --git a/plugins/dali-script-v8/src/controls/item-view-api.cpp b/plugins/dali-script-v8/src/controls/item-view-api.cpp new file mode 100644 index 0000000..4852a61 --- /dev/null +++ b/plugins/dali-script-v8/src/controls/item-view-api.cpp @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "item-view-api.h" + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include + +namespace Dali +{ + +namespace V8Plugin +{ + +namespace // unanmed namespace +{ + +Toolkit::ItemView GetItemView( v8::Isolate* isolate, const v8::FunctionCallbackInfo& args ) +{ + HandleWrapper* handleWrapper = HandleWrapper::Unwrap( isolate, args.This() ); + return Toolkit::ItemView::DownCast( handleWrapper->mHandle ); +} + +} //unanmed namespace + +/*************************************** + * ITEMVIEW API FUNCTIONS + ***************************************/ + +/** + * Constructor + * + * @for ItemView + * @constructor + * @method ItemView + * @return {Object} itemView + */ +Toolkit::Control ItemViewApi::New( const v8::FunctionCallbackInfo< v8::Value >& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + bool found( false ); + Toolkit::ItemFactory& factory = ItemFactoryWrapper::GetItemFactoryFromParams( 1, found, isolate, args ); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid ItemFactory parameter" ); + return Toolkit::Control(); + } + else + { + Toolkit::ItemView itemView = Toolkit::ItemView::New(factory); + ItemFactoryWrapper::SetItemView(factory, itemView); + return itemView; + } +} + +/** + * Query the number of layouts. + * + * @for ItemView + * @method getLayoutCount + * @return {Integer} The number of layouts. + */ +void ItemViewApi::GetLayoutCount( const v8::FunctionCallbackInfo< v8::Value >& args) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + args.GetReturnValue().Set( v8::Integer::New( isolate, itemView.GetLayoutCount() ) ); +} + +/** + * Add a layout + * + * @for ItemView + * @method addLayout + * @param {Integer} layout The layout to be added + * @example + * // layout is one of the following + * dali.ITEM_LAYOUT_LIST + * dali.ITEM_LAYOUT_GRID + * + * itemView.addLayout( dali.ITEM_LAYOUT_LIST ); + */ +void ItemViewApi::AddLayout( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int layout = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid layout parameter" ); + return; + } + + Toolkit::ItemLayoutPtr layoutPtr = Toolkit::DefaultItemLayout::New( static_cast(layout) ); + itemView.AddLayout( *layoutPtr ); +} + +/** + * Remove a layout. + * + * @for ItemView + * @method removeLayout + * @param {Integer} layoutIndex The index of the ItemView layouts which must be less than getLayoutCount(). + */ +void ItemViewApi::RemoveLayout( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int layoutIndex = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid index parameter" ); + return; + } + + itemView.RemoveLayout( layoutIndex ); +} + +/** + * Activate one of the layouts. This will resize the ItemView and relayout actors within the ItemView. + * + * @for ItemView + * @method activateLayout + * @param {Integer} layoutIndex The index of the ItemView layout which must be less than getLayoutCount(). + * @param {Object} targetSize An array of 3 numbers for the target ItemView and layout size. + * @param {Float} [durationSeconds] The time taken to relayout in seconds (0 by default for immediate). + */ +void ItemViewApi::ActivateLayout( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int layoutIndex = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 ); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid layout index parameter" ); + return; + } + + found = false; + Vector3 targetSize = V8Utils::GetVector3Parameter( PARAMETER_1, found, isolate, args ); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "Vector3 targetSize size parameter missing" ); + return; + } + + found = false; + float durationSeconds = V8Utils::GetFloatParameter( PARAMETER_2, found, isolate, args, 0.0f ); // 0 by default for immediate activation + + itemView.ActivateLayout( layoutIndex, targetSize, durationSeconds ); +} + +/** + * Retrieve the target size of an item in the given layout. + * This will return the default size for the layout unless overridden by calling setLayoutItemSize(). + * + * @for ItemView + * @method getItemSize + * @param {Integer} layoutIndex The index of the ItemView layout which must be less than getLayoutCount(). + * @param {Integer} itemId The ID of an item in the layout. + * @param {Object} targetLayoutSize An array of 3 numbers for the target ItemView and layout size. + * @return {Object} The target size of the item {x, y, z}. + */ +void ItemViewApi::GetItemSize( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int layoutIndex = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid layout index parameter" ); + return; + } + + found = false; + int itemId = V8Utils::GetIntegerParameter( PARAMETER_1, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid item ID parameter" ); + return; + } + + found = false; + Vector3 targetLayoutSize = V8Utils::GetVector3Parameter( PARAMETER_2, found, isolate, args ); + if( found ) + { + Toolkit::ItemLayoutPtr layoutPtr = itemView.GetLayout(layoutIndex); + Vector3 itemSize; + layoutPtr->GetItemSize( itemId, targetLayoutSize, itemSize ); + + v8::Local itemSizeObject = v8::Object::New( isolate ); + + itemSizeObject->Set( v8::String::NewFromUtf8( isolate, "x" ), v8::Integer::New( isolate, itemSize.width ) ); + itemSizeObject->Set( v8::String::NewFromUtf8( isolate, "y" ), v8::Integer::New( isolate, itemSize.height ) ); + itemSizeObject->Set( v8::String::NewFromUtf8( isolate, "z" ), v8::Integer::New( isolate, itemSize.depth ) ); + + args.GetReturnValue().Set( itemSizeObject ); + } + else + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid Vector3 target size parameter" ); + } +} + +/** + * Set the size of the item for the given layout which overrides the default item size for the layout. + * + * @for ItemView + * @method setItemSize + * @param {Integer} layoutIndex The index of the ItemView layout which must be less than getLayoutCount(). + * @param {Object} itemSize An array of 3 numbers for the size of the item. + * @example + * itemView.setLayoutItemSize( 0, [100.0, 50.0, 0.0] ); + */ +void ItemViewApi::SetItemSize( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int layoutIndex = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid layout index parameter" ); + return; + } + + found = false; + Vector3 itemSize = V8Utils::GetVector3Parameter( PARAMETER_1, found, isolate, args ); + if( found ) + { + Toolkit::ItemLayoutPtr layoutPtr = itemView.GetLayout(layoutIndex); + layoutPtr->SetItemSize( itemSize ); + } + else + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid item size parameter" ); + } +} + +/** + * Scroll the current layout to a particular item. + * If calling this with zero second of duration immediately after calling activateLayout(), + * it will not work unless the duration of relayout animation for activateLayout is also + * set to zero. + * + * @for ItemView + * @method scrollToItem + * @param {Integer} itemId The ID of an item in the layout. + * @param {Float} [durationSeconds] How long the scrolling takes in seconds (0 by default for instant scrolling to the particular item). + */ +void ItemViewApi::ScrollToItem( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int itemId = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid item Id parameter" ); + return; + } + + found = false; + float durationSeconds = V8Utils::GetFloatParameter( PARAMETER_1, found, isolate, args, 0.0f ); // 0 by default for instant scrolling + + itemView.ScrollToItem( itemId, durationSeconds ); +} + +/** + * Given the Item ID, this returns the accompanying actor. + * + * @for ItemView + * @method getItem + * @param {Integer} itemId The Item ID of the actor required. + * @return {Object} The Actor corresponding to the Item ID. + */ +void ItemViewApi::GetItem( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + int itemId = V8Utils::GetIntegerParameter( PARAMETER_0, found, isolate, args, 0 /* default */); + if( found ) + { + found = false; + Actor actor = itemView.GetItem( itemId ); + if( actor ) + { + found = true; + // wrap the actor + v8::Handle < v8::Object > wrappedActor = ActorWrapper::WrapActor( isolate, actor ); + args.GetReturnValue().Set( wrappedActor ); + } + } + + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid item ID" ); + return; + } +} + +/** + * Returns the Item ID of the specified actor. The actor must be an item of ItemView. + * + * @for ItemView + * @method getItemId + * @param {Object} actor The actor whose Item ID is required. + * @return {Integer} The Item ID of the item. + */ +void ItemViewApi::GetItemId( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + bool found( false ); + Actor actor = V8Utils::GetActorParameter( 0, found, isolate, args ); + if( found ) + { + args.GetReturnValue().Set( itemView.GetItemId(actor) ); + } + else + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid item actor parameter" ); + return; + } +} + +/** + * Get the range of items that are currently in ItemView. + * + * @for ItemView + * @method getItemsRange + * @return {Object} The range of items in the item ID {begin, end}. + */ +void ItemViewApi::GetItemsRange( const v8::FunctionCallbackInfo& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + Toolkit::ItemView itemView = GetItemView( isolate, args ); + + Toolkit::ItemRange range(0, 0); + itemView.GetItemsRange(range); + + v8::Local itemRangeObject = v8::Object::New( isolate ); + + itemRangeObject->Set( v8::String::NewFromUtf8( isolate, "begin" ), v8::Integer::New( isolate, range.begin ) ); + itemRangeObject->Set( v8::String::NewFromUtf8( isolate, "end" ), v8::Integer::New( isolate, range.end ) ); + + args.GetReturnValue().Set( itemRangeObject ); +} + +} // namespace V8Plugin + +} // namespace Dali diff --git a/plugins/dali-script-v8/src/controls/item-view-api.h b/plugins/dali-script-v8/src/controls/item-view-api.h new file mode 100644 index 0000000..7f56653 --- /dev/null +++ b/plugins/dali-script-v8/src/controls/item-view-api.h @@ -0,0 +1,59 @@ +#ifndef __DALI_V8PLUGIN_ITEM_VIEW_API_H__ +#define __DALI_V8PLUGIN_ITEM_VIEW_API_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace V8Plugin +{ + +namespace ItemViewApi +{ + + /** + * constructor + */ + Toolkit::Control New( const v8::FunctionCallbackInfo< v8::Value >& args ); + + /** + * ItemView API. See item-view.h for description of functions + */ + void GetLayoutCount( const v8::FunctionCallbackInfo< v8::Value >& args); + void AddLayout( const v8::FunctionCallbackInfo< v8::Value >& args ); + void RemoveLayout( const v8::FunctionCallbackInfo< v8::Value >& args ); + void ActivateLayout( const v8::FunctionCallbackInfo< v8::Value >& args); + void GetItemSize( const v8::FunctionCallbackInfo< v8::Value >& args); + void SetItemSize( const v8::FunctionCallbackInfo< v8::Value >& args); + void ScrollToItem( const v8::FunctionCallbackInfo< v8::Value >& args); + void GetItem( const v8::FunctionCallbackInfo< v8::Value >& args); + void GetItemId( const v8::FunctionCallbackInfo< v8::Value >& args); + void GetItemsRange( const v8::FunctionCallbackInfo< v8::Value >& args); + +}; // namespace ItemViewApi + +} // namespace V8Plugin + +} // namespace Dali + +#endif // header __DALI_V8PLUGIN_ITEM_VIEW_API_H__ diff --git a/plugins/dali-script-v8/src/dali-wrapper.cpp b/plugins/dali-script-v8/src/dali-wrapper.cpp index 132dc5e..92719c7 100644 --- a/plugins/dali-script-v8/src/dali-wrapper.cpp +++ b/plugins/dali-script-v8/src/dali-wrapper.cpp @@ -23,12 +23,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -70,11 +72,12 @@ const ApiFunction ConstructorFunctionTable[]= { "Actor", ActorWrapper::NewActor }, { "CameraActor", ActorWrapper::NewActor }, { "Layer", ActorWrapper::NewActor }, - { "Control", ActorWrapper::NewControl }, + { "Control", ControlWrapper::NewControl }, { "ResourceImage", ImageWrapper::NewImage }, { "BufferImage", ImageWrapper::NewImage }, { "FrameBufferImage", ImageWrapper::NewImage }, { "Animation", AnimationWrapper::NewAnimation}, + { "ItemFactory", ItemFactoryWrapper::NewItemFactory}, { "Shader", ShaderWrapper::NewShader}, { "Sampler", SamplerWrapper::NewSampler}, { "Material", MaterialWrapper::NewMaterial}, diff --git a/plugins/dali-script-v8/src/object/handle-wrapper.cpp b/plugins/dali-script-v8/src/object/handle-wrapper.cpp index 2915670..be1739d 100644 --- a/plugins/dali-script-v8/src/object/handle-wrapper.cpp +++ b/plugins/dali-script-v8/src/object/handle-wrapper.cpp @@ -42,6 +42,7 @@ namespace // un-named name space const ApiFunction HandleFunctionTable[]= { { "RegisterAnimatableProperty", HandleWrapper::RegisterAnimatableProperty }, + { "RegisterCustomProperty", HandleWrapper::RegisterCustomProperty }, }; const unsigned int HandleFunctionTableCount = sizeof(HandleFunctionTable)/sizeof(HandleFunctionTable[0]); @@ -212,8 +213,8 @@ void HandleWrapper::AddInterceptsToTemplate( v8::Isolate* isolate, v8::Local& args ) @@ -251,6 +252,75 @@ void HandleWrapper::RegisterAnimatableProperty( const v8::FunctionCallbackInfo< } } +/** + * Register a new custom property. + * + * The object should support dynamic properties. + * Property names must be unused. + * Property indices are unique to each registered custom property in a given object. + * Properties can be set as non animatable using property attributes. + * returns dali.PROPERTY_INVALID_INDEX if registration failed. + * + * @method registerCustomProperty + * @for Handle + * @param {string} name The name of the property. + * @param {Object} propertyValue The new value of the property. + * @param {integer} accessMode The property access mode (writable, animatable etc). + * @return {integer} The index of the property or dali.PROPERTY_INVALID_INDEX if registration failed + * @example + * + * // access mode is one of the following + * dali.PROPERTY_READ_ONLY + * dali.PROPERTY_READ_WRITE + * dali.PROPERTY_ANIMATABLE + * + * var cellIndexPropertyIndex = actor.registerCustomProperty("cellIndex", 2, dali.PROPERTY_READ_WRITE); + * var myCustomPropertyIndex = handle.registerCustomProperty("myCustomProperty", [10.0, 25.0, 0.0], dali.PROPERTY_READ_ONLY); + * + */ +void HandleWrapper::RegisterCustomProperty( const v8::FunctionCallbackInfo< v8::Value >& args ) +{ + v8::Isolate* isolate = args.GetIsolate(); + v8::HandleScope handleScope( isolate ); + + // unwrap the object + HandleWrapper* handleWrapper = Unwrap( isolate, args.This() ); + if( !handleWrapper ) + { + return; + } + + Handle handle = handleWrapper->mHandle; + + bool found( false ); + std::string propertyName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args ); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "bad property name parameter" ); + return; + } + + found = false; + Dali::Property::Value daliPropertyValue = V8Utils::GetPropertyValueParameter(PARAMETER_1, found, isolate, args ); + if( !found || Dali::Property::NONE == daliPropertyValue.GetType() ) + { + DALI_SCRIPT_EXCEPTION( isolate, "bad property value parameter" ); + return; + } + + found = false; + int accessMode = V8Utils::GetIntegerParameter( PARAMETER_2, found, isolate, args, 0 /* default */); + if( !found ) + { + DALI_SCRIPT_EXCEPTION( isolate, "invalid access mode parameter" ); + return; + } + else + { + args.GetReturnValue().Set( v8::Integer::New( isolate, handle.RegisterProperty( propertyName, daliPropertyValue, static_cast(accessMode) ) ) ); + } +} + } // namespace V8Plugin } // namespace Dali diff --git a/plugins/dali-script-v8/src/object/handle-wrapper.h b/plugins/dali-script-v8/src/object/handle-wrapper.h index 2e612c7..7356f01 100644 --- a/plugins/dali-script-v8/src/object/handle-wrapper.h +++ b/plugins/dali-script-v8/src/object/handle-wrapper.h @@ -81,6 +81,13 @@ public: */ static void RegisterAnimatableProperty( const v8::FunctionCallbackInfo< v8::Value >& args ); + /** + * @brief Register a custom property for a JavaScript object that + * contains a Dali Handle. + * @param[in] args v8 function call arguments interpreted + */ + static void RegisterCustomProperty( const v8::FunctionCallbackInfo< v8::Value >& args ); + Handle GetHandle() { return mHandle; } Handle mHandle; ConnectionTracker mConnectionTracker; diff --git a/plugins/dali-script-v8/src/shared/base-wrapped-object.h b/plugins/dali-script-v8/src/shared/base-wrapped-object.h index db1c8a8..0bd9840 100644 --- a/plugins/dali-script-v8/src/shared/base-wrapped-object.h +++ b/plugins/dali-script-v8/src/shared/base-wrapped-object.h @@ -80,6 +80,8 @@ public: IMAGE_ATTRIBUTES, ACTOR, ACTOR_PROPERTY, + ITEMVIEW, + ITEMFACTORY, RENDER_TASK, RENDER_TASK_LIST, TIMER, diff --git a/plugins/dali-script-v8/src/utils/v8-utils.cpp b/plugins/dali-script-v8/src/utils/v8-utils.cpp index 4d09da9..b77d458 100644 --- a/plugins/dali-script-v8/src/utils/v8-utils.cpp +++ b/plugins/dali-script-v8/src/utils/v8-utils.cpp @@ -149,6 +149,118 @@ void GetModuleName( const std::string& fileName, std::string& moduleName ) } } +bool IsPropertyMapIdentical(Property::Map map1, Property::Map map2) +{ + bool dirty = false; + + // Compare number of properties + if ( map1.Count() != map2.Count() ) + { + dirty = true; + } + else + { + for ( unsigned int i = 0, count = map1.Count(); i < count; ++i ) + { + // Compare the key first + if(map1.GetKey(i) != map2.GetKey(i)) + { + dirty = true; + } + else + { + Property::Value& value = map1.GetValue(i); + Property::Value& newValue = map2.GetValue(i); + + // Compare the value type + if(value.GetType() != newValue.GetType()) + { + dirty = true; + } + else + { + // Compare the value + switch( value.GetType() ) + { + case Property::BOOLEAN: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::FLOAT: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::INTEGER: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::RECTANGLE: + { + dirty = ( value.Get< Rect >() != newValue.Get< Rect >() ); + break; + } + case Property::VECTOR2: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::VECTOR3: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::VECTOR4: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::MATRIX3: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::MATRIX: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::ROTATION: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::STRING: + { + dirty = ( value.Get() != newValue.Get() ); + break; + } + case Property::MAP: + { + dirty = ( !IsPropertyMapIdentical( value.Get(), newValue.Get() ) ); + break; + } + default: + { + break; + } + } + } + } + + if(dirty) + { + // Different already, no need any further comparison + break; + } + } + } + + return !dirty; +} + void ReportException( v8::Isolate* isolate, v8::TryCatch* tryCatch) { v8::HandleScope handleScope( isolate ); @@ -879,7 +991,7 @@ void CreatePropertyMap( v8::Isolate* isolate, const Property::Map& map, v8::Loca return; } - for( unsigned int index = 0; index < map.Count() - 1; ++index ) + for( unsigned int index = 0; index < map.Count(); ++index ) { const std::string& key = map.GetKey( index ); Property::Value& value = map.GetValue( index ); diff --git a/plugins/dali-script-v8/src/utils/v8-utils.h b/plugins/dali-script-v8/src/utils/v8-utils.h index 1551868..5a86f39 100644 --- a/plugins/dali-script-v8/src/utils/v8-utils.h +++ b/plugins/dali-script-v8/src/utils/v8-utils.h @@ -96,6 +96,14 @@ void GetFileName( const std::string& fullPathName, std::string& fileName); void GetModuleName( const std::string& fileName, std::string& moduleName ); /** + * Compare whether two DALi property maps are identical + * @param[in] map1 The first property map to be compared + * @param[in] map2 The second property map to be compared + * @return true if the two specified property maps are identical or false if not. + */ +bool IsPropertyMapIdentical(Property::Map map1, Property::Map map2); + +/** * Report an exception by writing as a warning to the Dali Log * * @param[in] try_catch The v8 TryCatch exception object