UNPKG

neft

Version:

Universal Platform

279 lines (220 loc) 9.71 kB
# Native 'use strict' utils = require 'src/utils' log = require 'src/log' assert = require 'src/assert' colorUtils = require 'src/renderer/utils/color' IS_NATIVE = process.env.NEFT_NATIVE try {callNativeFunction, onNativeEvent} = require 'src/native' module.exports = (Renderer, Impl, itemUtils) -> class Native extends Renderer.Item @__name__ = 'Native' @__path__ = 'Renderer.Native' ## *Native* Native.New([*Object* options]) @New = (opts) -> item = new @ itemUtils.Object.initialize item, opts @Initialize? item item ## Native.defineProperty(*Object* config) Defines new property with the given name. For each property, signal `onXYZChange` is created, where `XYZ` is the given name. `config` parameter must be an object with specified keys: - `enabled` - whether it's supported on current platform, - `name` - name of the property, - `type` - type of predefined condifuration described below, - `defaultValue`, - `setter`, - `getter`, - `developmentSetter` - `implementationValue` - function returning value passed to the implementation. ### Predefined types PROPERTY_TYPES = Object.create null #### text PROPERTY_TYPES.text = -> defaultValue: '' developmentSetter: (val) -> assert.isString val #### number PROPERTY_TYPES.number = -> defaultValue: 0 developmentSetter: (val) -> assert.isFloat val #### boolean PROPERTY_TYPES.boolean = -> defaultValue: false developmentSetter: (val) -> assert.isBoolean val #### color PROPERTY_TYPES.color = (config) -> defaultValue: '' developmentSetter: (val) -> assert.isString val implementationValue: do -> RESOURCE_REQUEST = property: 'color' (val) -> val = Impl.resources?.resolve(val, RESOURCE_REQUEST) or val if IS_NATIVE if val? colorUtils.toRGBAHex val, config.defaultValue else null else val #### item PROPERTY_TYPES.item = (config) -> defaultValue: null developmentSetter: (val) -> if val? assert.instanceOf val, Renderer.Item implementationValue: (val) -> if IS_NATIVE if val? val._impl.id else null else val @defineProperty = (config) -> itemName = @__name__ properties = @_properties ||= [] config = utils.clone config assert.isString itemName, ''' NativeItem.__name__ unique name must be specified ''' assert.isObject config, ''' NativeItem.defineProperty config parameter must be an object ''' assert.isString config.name, ''' NativeItem property name must be a string ''' assert.isNotDefined properties[config.name], """ Property #{config.name} is already defined """ assert.isDefined PROPERTY_TYPES[config.type], """ Unknown property type #{config.type} """ if config.type # type if typeConfigFunc = PROPERTY_TYPES[config.type] typeConfig = typeConfigFunc(config) for key, val of typeConfig if key not of config config[key] = val # constructor config.constructor = @ # internalName config.internalName = itemUtils.getPropInternalName config.name # implementation config.implementation = do -> if config.enabled is false return utils.NOP ctorName = utils.capitalize itemName name = utils.capitalize config.name if IS_NATIVE funcName = "rendererSet#{ctorName}#{name}" (val) -> callNativeFunction funcName, @_impl.id, val else funcName = "set#{ctorName}#{name}" (val) -> Impl[funcName]?.call @, val # save properties.push config # create itemUtils.defineProperty config ## *Native* Native::constructor() : *Item* constructor: -> super() @_autoWidth = true @_autoHeight = true @_width = -1 @_height = -1 # save properties with default values if properties = @constructor._properties for property in properties @[property.internalName] = property.defaultValue _width: -1 getter = utils.lookupGetter @::, 'width' itemWidthSetter = utils.lookupSetter @::, 'width' utils.defineProperty @::, 'width', null, getter, do (_super = itemWidthSetter) -> (val) -> if @_autoWidth = val is -1 Impl.updateNativeSize.call @ else _super.call @, val return _height: -1 getter = utils.lookupGetter @::, 'height' itemHeightSetter = utils.lookupSetter @::, 'height' utils.defineProperty @::, 'height', null, getter, do (_super = itemHeightSetter) -> (val) -> if @_autoHeight = val is -1 Impl.updateNativeSize.call @ else _super.call @, val return ## Native::set(*String* propName, *Any* val) set: (name, val) -> assert.isString name, "NativeItem.set name must be a string, but #{name} given" ctorName = utils.capitalize @constructor.__name__ id = @_impl.id name = utils.capitalize name if IS_NATIVE funcName = "rendererSet#{ctorName}#{name}" callNativeFunction funcName, id, val else funcName = "set#{ctorName}#{name}" Impl[funcName]?.call @, val return ## Native::call(*String* funcName, *Any* args...) call: (name, args...) -> assert.isString name, "NativeItem.call name must be a string, but #{name} given" ctorName = utils.capitalize @constructor.__name__ id = @_impl.id name = utils.capitalize name if IS_NATIVE funcName = "rendererCall#{ctorName}#{name}" callArgs = [funcName, id, args...] callNativeFunction callArgs... else funcName = "call#{ctorName}#{name}" Impl[funcName]?.apply @, args return ## Native::on(*String* eventName, *Function* listener) # nativeEventName -> item id -> [item, listeners...] eventListeners = Object.create null createNativeEventListener = (listeners, eventName) -> (id) -> unless itemListeners = listeners[id] log.warn "Got a native event '#{eventName}' for an item which " + "didn't register a listener on this event; check if you " + "properly call 'on()' method with a signal listener" return length = arguments.length args = new Array length - 1 for i in [0...length - 1] by 1 args[i] = arguments[i + 1] item = itemListeners[0] for i in [1...itemListeners.length] by 1 itemListeners[i].apply item, args return on: (name, func) -> assert.isString name, "NativeItem.on name must be a string, but #{name} given" assert.isFunction func, """ NativeItem.on listener must be a function, but #{func} given """ name = utils.capitalize name if IS_NATIVE ctorName = utils.capitalize @constructor.__name__ eventName = "rendererOn#{ctorName}#{name}" unless listeners = eventListeners[eventName] listeners = eventListeners[eventName] = Object.create(null) onNativeEvent eventName, createNativeEventListener(listeners, eventName) itemListeners = listeners[@_impl.id] ?= [@] itemListeners.push func else eventName = "on#{name}" @_impl[eventName]?.connect func return Native