2086 lines
68 KiB
XML
2086 lines
68 KiB
XML
<?rokuml version="1.0" encoding="utf-8" ?>
|
|
<!--********** Copyright 2019 Roku Corp. All Rights Reserved. **********-->
|
|
|
|
<component name="TrackerTask" extends="Task">
|
|
|
|
<interface>
|
|
<field id="event" type="assocarray"/>
|
|
<field id="isExternallyExposed" type="boolean" value="true"/>
|
|
|
|
<function name="UIThread_init"/>
|
|
<function name="UIThread_showSelectorView"/>
|
|
<function name="UIThread_hideSelectorView"/>
|
|
|
|
<function name="UIThread_selectNode"/>
|
|
<function name="UIThread_updateNode"/>
|
|
<function name="UIThread_getNodeData"/>
|
|
|
|
<function name="UIThread_getItemList"/>
|
|
<function name="UIThread_getNodeTree"/>
|
|
<function name="UIThread_getNodeById"/>
|
|
<function name="UIThread_getNodeByName"/>
|
|
|
|
<function name="UIThread_addChild"/>
|
|
<function name="UIThread_removeChild"/>
|
|
<function name="UIThread_moveChild"/>
|
|
|
|
<function name="UIThread_setField"/>
|
|
<function name="UIThread_removeField"/>
|
|
|
|
<function name="UIThread_setFocus"/>
|
|
<function name="UIThread_selectFocusedNode"/>
|
|
|
|
<function name="UIThread_setBoundingRect"/>
|
|
|
|
</interface>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script type = "text/brightscript" >
|
|
<![CDATA[
|
|
|
|
' RALE_Config - RALE config singleton class
|
|
' @return {object} - RALE config properties
|
|
Function RALE_Config() as Object
|
|
if m.appConfig = Invalid then m.appConfig = RALE_InitConfig()
|
|
return m.appConfig
|
|
End Function
|
|
|
|
' RALE_InitConfig - RALE config init function. Defines all config properties
|
|
' @return {object} - RALE config properties
|
|
Function RALE_InitConfig() as Object
|
|
this = {
|
|
bufferSize: 1024,
|
|
minSocketPort: 49152,
|
|
maxSocketPort: 65535,
|
|
screensaverResetTimeout: 30000,
|
|
commandTimeout: 10000
|
|
}
|
|
|
|
return this
|
|
End Function
|
|
|
|
|
|
' CreateSelectorView - Selector (live) view class constructor
|
|
' @return {object} - selector (live) view
|
|
Function CreateSelectorView() as Object
|
|
view = CreateObject("roSGNode", "Group")
|
|
|
|
m.resolution = m.top.getScene().getField("currentDesignResolution")
|
|
m.resWidth = m.resolution.width
|
|
m.resHeight = m.resolution.height
|
|
|
|
children = [
|
|
{subtype : "Rectangle", fields : {id : "l"}}
|
|
{subtype : "Rectangle", fields : {id : "r"}}
|
|
{subtype : "Rectangle", fields : {id : "b"}}
|
|
{subtype : "Rectangle", fields : {id : "t"}}
|
|
|
|
{subtype : "Rectangle", fields : {id : "horiz"}}
|
|
{subtype : "Rectangle", fields : {id : "vert"}}
|
|
|
|
|
|
{subtype : "Rectangle", fields : {id : "leftLine"}}
|
|
{subtype : "Rectangle", fields : {id : "topLine"}}
|
|
{subtype : "Rectangle", fields : {id : "rightLine"}}
|
|
{subtype : "Rectangle", fields : {id : "bottomLine"}}
|
|
|
|
{subtype : "Label", fields : {id : "leftCords"}}
|
|
{subtype : "Label", fields : {id : "topCords"}}
|
|
{subtype : "Label", fields : {id : "rightCords"}}
|
|
{subtype : "Label", fields : {id : "bottomCords"}}
|
|
|
|
{subtype : "Rectangle", fields : {id : "fill", color : "#ffffff44"}}
|
|
{subtype : "Timer", fields : {id : "timer", duration : 1 / 60, repeat : true}}
|
|
]
|
|
|
|
viewObject = NodeUtils_AddChildrenToNode(view, children)
|
|
childrenMap = {}
|
|
for each child in viewObject.children
|
|
node = child.node
|
|
childrenMap[node.id] = node
|
|
end for
|
|
|
|
interface = [
|
|
{id:"width", type:"float", value : "1280", onChange : "SelectorView_UpdateView"}
|
|
{id:"height", type:"float", value : "40", onChange : "SelectorView_UpdateView"}
|
|
{id:"border", type:"float", value : "2", onChange : "SelectorView_UpdateView"}
|
|
{id:"oldBoundingRect", type:"assocarray" }
|
|
{id:"boundingRect", type:"assocarray", onChange : "SelectorView_UpdateViewFromBRect"}
|
|
{id:"color", type:"color", value : "#FFFFFF", onChange : "SelectorView_UpdateColors"}
|
|
{id:"attachedView", type:"node", onChange : "SelectorView_AttachToView"}
|
|
{id:"isExternallyExposed", type:"boolean", value : "true"}
|
|
{id:"childrenMap", type:"assocarray", value : childrenMap}
|
|
]
|
|
NodeUtils_AddInterfaceToNode(view, interface)
|
|
|
|
timer = view.childrenMap.timer
|
|
timer.observeField("fire","SelectorView_UpdateViewPosition")
|
|
timer.control = "start"
|
|
|
|
return view
|
|
End Function
|
|
|
|
' NodeUtils_AddInterfaceToNode - Adds interface to node
|
|
' @param {object} node - node
|
|
' @param {object} interface - interface
|
|
' @return {boolean} - is interface was added
|
|
Function NodeUtils_AddInterfaceToNode(node, interface as Object) as Boolean
|
|
if node = invalid OR interface = invalid then return false
|
|
for each field in interface
|
|
NodeUtils_AddNodeInterfaceField(node, field)
|
|
end for
|
|
return true
|
|
End Function
|
|
|
|
' NodeUtils_AddNodeInterfaceField - Adds interface field to node
|
|
' @param {object} node - node
|
|
' @param {object} fieldConfig - field config
|
|
' @return {boolean} - is interface was added
|
|
Function NodeUtils_AddNodeInterfaceField(node, fieldConfig as Object) as Boolean
|
|
if node = invalid OR fieldConfig = invalid then return false
|
|
if fieldConfig.id = invalid then return false
|
|
if fieldConfig.type = invalid then return false
|
|
|
|
if fieldConfig.alwaysNotify = invalid then fieldConfig.alwaysNotify = true
|
|
|
|
if node.hasField(fieldConfig.id) then return false
|
|
|
|
node.addField(fieldConfig.id, fieldConfig.type, fieldConfig.alwaysNotify)
|
|
|
|
if not node.hasField(fieldConfig.id) then return false
|
|
|
|
if fieldConfig.value <> invalid then
|
|
node[fieldConfig.id] = fieldConfig.value
|
|
end if
|
|
|
|
if fieldConfig.onChange <> invalid then
|
|
node.observeField(fieldConfig.id, fieldConfig.onChange)
|
|
end if
|
|
|
|
return true
|
|
End Function
|
|
|
|
' NodeUtils_AddChildrenToNode - Adds children to node
|
|
' @param {object} node - node
|
|
' @param {object} childrenConfig - children config
|
|
' @return {object} - view object
|
|
Function NodeUtils_AddChildrenToNode(node, childrenConfig as Object) as Object
|
|
if node = invalid then return invalid
|
|
viewObject = {node : node, children : []}
|
|
if childrenConfig <> invalid then
|
|
for each childConfig in childrenConfig
|
|
childObject = NodeUtils_AddChildToNode(node, childConfig)
|
|
viewObject.children.push(childObject)
|
|
end for
|
|
end if
|
|
|
|
return viewObject
|
|
End Function
|
|
|
|
' NodeUtils_AddChildToNode - Adds child to node
|
|
' @param {object} node - node
|
|
' @param {object} childConfig - child config
|
|
' @return {object} - view object
|
|
Function NodeUtils_AddChildToNode(node, childConfig) as Object
|
|
if node = invalid or childConfig = invalid then return invalid
|
|
if childConfig.subtype = invalid then return invalid
|
|
view = node.CreateChild(childConfig.subtype)
|
|
if view = invalid then return invalid
|
|
if childConfig.fields <> invalid then view.setFields(childConfig.fields)
|
|
return NodeUtils_AddChildrenToNode(view, childConfig.children)
|
|
End Function
|
|
|
|
' NumberToFixed - formats a number using fixed-point notation
|
|
' @param {float, double} number - formated number
|
|
' @param {integer} digits - the number of digits to appear after the decimal point
|
|
' @return {string} - a string representing the given number using fixed-point notation
|
|
Function NumberToFixed(number, digits) as String
|
|
str = number.toStr()
|
|
arr = str.split(".")
|
|
|
|
if arr.count() > 1 and digits > 0 then
|
|
return arr[0] + "." + Left(arr[1], digits)
|
|
end if
|
|
|
|
return arr[0]
|
|
End Function
|
|
|
|
' SelectorView_UpdateView - width, height and border change event handler. Updates Selector (live) view
|
|
' @param {object} event - event data
|
|
Sub SelectorView_UpdateView(event)
|
|
node = event.getRoSGNode()
|
|
border = node.border
|
|
width = node.width
|
|
height = node.height
|
|
x = node.boundingRect.x
|
|
y = node.boundingRect.y
|
|
rightPos = x + width + border*2
|
|
bottomPos = y + height + border*2
|
|
|
|
l = node.childrenMap.l
|
|
l.width = border
|
|
l.height = height + border*2
|
|
l.translation = [-border, -border]
|
|
|
|
r = node.childrenMap.r
|
|
r.width = border
|
|
r.height = height + border*2
|
|
r.translation = [width, -border]
|
|
|
|
t = node.childrenMap.t
|
|
t.width = width + border*2
|
|
t.height = border
|
|
t.translation = [-border, -border]
|
|
|
|
b = node.childrenMap.b
|
|
b.width = width + border*2
|
|
b.height = border
|
|
b.translation = [-border, height]
|
|
|
|
horiz = node.childrenMap.horiz
|
|
horiz.width = width
|
|
horiz.height = border
|
|
horiz.translation = [0, (height - border) / 2]
|
|
|
|
vert = node.childrenMap.vert
|
|
vert.width = border
|
|
vert.height = height
|
|
vert.translation = [(width - border) / 2, 0]
|
|
|
|
leftLine = node.childrenMap.leftLine
|
|
leftLine.width = x
|
|
leftLine.height = border
|
|
leftLine.translation = [-x, (height - border) / 2]
|
|
|
|
topLine = node.childrenMap.topLine
|
|
topLine.width = border
|
|
topLine.height = y
|
|
topLine.translation = [(width - border) / 2, -y]
|
|
|
|
rightLine = node.childrenMap.rightLine
|
|
rightLine.width = m.resWidth - x + 10
|
|
rightLine.height = border
|
|
rightLine.translation = [width + border, (height - border) / 2]
|
|
|
|
bottomLine = node.childrenMap.bottomLine
|
|
bottomLine.width = border
|
|
bottomLine.height = m.resHeight - y + 10
|
|
bottomLine.translation = [(width - border) / 2, height + border]
|
|
|
|
leftCords = node.childrenMap.leftCords
|
|
leftCords.font.size = 20
|
|
leftCords.color = "#FF0000"
|
|
leftCords.text = NumberToFixed(x, 0)
|
|
leftCords.translation = [-x/2 - 10, (height - border) / 2 - 20]
|
|
|
|
topCords = node.childrenMap.topCords
|
|
topCords.font.size = 20
|
|
topCords.color = "#FF0000"
|
|
topCords.text = NumberToFixed(y, 0)
|
|
topCords.translation = [(width - border) / 2 + 10, -y/2 - 10]
|
|
|
|
rightCords = node.childrenMap.rightCords
|
|
rightCords.font.size = 20
|
|
rightCords.color = "#FF0000"
|
|
rightCords.text = NumberToFixed(m.resWidth - x - width, 0)
|
|
rightCords.translation = [width + (m.resWidth - rightPos)/2 - 5, (height - border) / 2 - 20]
|
|
|
|
bottomCords = node.childrenMap.bottomCords
|
|
bottomCords.font.size = 20
|
|
bottomCords.color = "#FF0000"
|
|
bottomCords.text = NumberToFixed(m.resHeight - y - height, 0)
|
|
bottomCords.translation = [(width - border) / 2 + 10, height + (m.resHeight - bottomPos)/2 - 5]
|
|
|
|
fill = node.childrenMap.fill
|
|
fill.width = width
|
|
fill.height = height
|
|
End Sub
|
|
|
|
' SelectorView_UpdateColors - color change event handler. Updates Selector (live) view color
|
|
' @param {object} event - event data
|
|
Sub SelectorView_UpdateColors(event)
|
|
node = event.getRoSGNode()
|
|
for each view in node.getchildren(-1,0)
|
|
if view.isSubtype("Rectangle") and view.id <> "fill" then view.color = node.color
|
|
end for
|
|
End Sub
|
|
|
|
' SelectorView_UpdateViewFromBRect - boundingRect change event handler.
|
|
' Updates Selector (live) view translation, width and height
|
|
' @param {object} event - event data
|
|
Sub SelectorView_UpdateViewFromBRect(event)
|
|
node = event.getRoSGNode()
|
|
boundingRect = node.boundingRect
|
|
if boundingRect <> Invalid then
|
|
node.setFields({
|
|
translation : [boundingRect.x, boundingRect.y]
|
|
width : boundingRect.width
|
|
height : boundingRect.height
|
|
})
|
|
end if
|
|
End Sub
|
|
|
|
' isBoundingRectChanged - checks is bounding rect was changed
|
|
' @param {object} br - node bounding rect
|
|
' @param {object} node - node
|
|
' @return {boolean} - true if node bounding rect was changed
|
|
Sub isBoundingRectChanged(br, node) as Boolean
|
|
o = node.oldBoundingRect
|
|
if o = Invalid then
|
|
node.oldBoundingRect = br
|
|
return true
|
|
end if
|
|
if o.x = br.x and o.y = br.y and o.width = br.width and o.height = br.height then
|
|
return false
|
|
else
|
|
node.oldBoundingRect = br
|
|
return true
|
|
end if
|
|
End Sub
|
|
|
|
' SelectorView_UpdateViewPosition - interval event handler. Updates selector (live) view position
|
|
' @param {object} event - node bounding rect
|
|
Sub SelectorView_UpdateViewPosition(event)
|
|
timer = event.getRoSGNode()
|
|
node = timer.getparent()
|
|
|
|
if node.attachedView <> Invalid then
|
|
boundingRect = node.attachedView.sceneboundingRect()
|
|
else
|
|
boundingRect = {x: -100, y: -100, width: 0, height: 0}
|
|
end if
|
|
|
|
if isBoundingRectChanged(boundingRect, node) then
|
|
node.boundingRect = boundingRect
|
|
end if
|
|
End Sub
|
|
|
|
|
|
' getCommandMap - Defines map that contains all RALE commands handlers
|
|
' @return {object} - handlers map
|
|
Sub getCommandMap() as Object
|
|
return {
|
|
"init" : "UIThread_init",
|
|
|
|
' Config commands
|
|
"showSelectorView" : "UIThread_showSelectorView",
|
|
"hideSelectorView" : "UIThread_hideSelectorView",
|
|
|
|
' Node commands
|
|
"selectNode" : "UIThread_selectNode",
|
|
"updateNode" : "UIThread_updateNode",
|
|
"getNodeData" : "UIThread_getNodeData",
|
|
|
|
' Tree View commands
|
|
"getItemList" : "UIThread_getItemList",
|
|
"getNodeTree" : "UIThread_getNodeTree",
|
|
"getNodeById" : "UIThread_getNodeById",
|
|
"getNodeByName" : "UIThread_getNodeByName",
|
|
|
|
' Children commands
|
|
"addChild" : "UIThread_addChild",
|
|
"removeChild" : "UIThread_removeChild",
|
|
"moveChild" : "UIThread_moveChild",
|
|
|
|
' Field commands
|
|
"setField" : "UIThread_setField",
|
|
"removeField" : "UIThread_removeField",
|
|
|
|
' Focus commands
|
|
"setFocus" : "UIThread_setFocus",
|
|
"selectFocusedNode" : "UIThread_selectFocusedNode",
|
|
|
|
' Bounding Rect commands
|
|
"setBoundingRect" : "UIThread_setBoundingRect"
|
|
}
|
|
End Sub
|
|
|
|
' callCommand - Call RALE command functuin from UI thread
|
|
' @param {string} command - command name
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of RALE command
|
|
Sub callCommand(command, args) as Object
|
|
return m.top.callFunc(command, args)
|
|
End Sub
|
|
|
|
' UIThread_init - RALE "init" command
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Contains RALE version
|
|
Sub UIThread_init(args) as Object
|
|
root = m.top.GetScene()
|
|
|
|
m.currentNode = root
|
|
m.currentPath = []
|
|
|
|
if m.selectorView = Invalid then
|
|
m.selectorView = CreateSelectorView()
|
|
m.selectorView.color = "#ff0000"
|
|
m.selectorView.opacity = 0.6
|
|
m.showSelectorView = true
|
|
root.appendChild(m.selectorView)
|
|
end if
|
|
return { raleVersion: m.raleVersion }
|
|
End Sub
|
|
|
|
'=======================
|
|
' Config commands
|
|
'=======================
|
|
|
|
' UIThread_showSelectorView - RALE "showSelectorView" command handler. Shows Selector (Live) View
|
|
' @param {object} args - command arguments
|
|
Sub UIThread_showSelectorView(args) as Object
|
|
m.showSelectorView = true
|
|
setSelectorView(m.currentNode, type(m.currentNode), m.currentPath)
|
|
End Sub
|
|
|
|
' UIThread_hideSelectorView - RALE "hideSelectorView" command handler. Hides Selector (Live) View
|
|
' @param {object} args - command arguments
|
|
Sub UIThread_hideSelectorView(args) as Object
|
|
m.showSelectorView = false
|
|
setSelectorView(m.currentNode, type(m.currentNode), m.currentPath)
|
|
End Sub
|
|
|
|
'=======================
|
|
' Node commands
|
|
'=======================
|
|
|
|
' UIThread_selectNode - RALE "selectNode" command handler. Selects node by path
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Contains node path and node data (id, type, fields, layout etc.)
|
|
Sub UIThread_selectNode(args) as Object
|
|
path = args["path"]
|
|
|
|
root = m.top.getScene()
|
|
node = RALE_getNodeByPath(root, path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
|
|
nodeType = type(node)
|
|
|
|
if nodeType <> "roSGNode" and nodeType = "roArray" and nodeType = "roAssociativeArray" then
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
|
|
if nodeType = "roSGNode" and node.isExternallyExposed <> Invalid then
|
|
return getError("Node Is Externally Exposed")
|
|
end if
|
|
|
|
if nodeType <> "roSGNode" or not node.IsSameNode(m.currentNode) then
|
|
m.currentPath = path
|
|
m.currentNode = node
|
|
end if
|
|
|
|
setSelectorView(node, nodeType, path)
|
|
|
|
return {
|
|
path: m.currentPath,
|
|
node: getNodeData(m.currentNode, m.currentPath, root)
|
|
}
|
|
End Sub
|
|
|
|
' UIThread_updateNode - RALE "updateNode" command handler. Updates selected node
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Contains node path and data (id, type, fields, layout etc.)
|
|
Sub UIThread_updateNode(args) as Object
|
|
return {
|
|
path: m.currentPath,
|
|
node: getNodeData(m.currentNode, m.currentPath, Invalid)
|
|
}
|
|
End Sub
|
|
|
|
' UIThread_getNodeData - RALE "getNodeData" command handler. Returns selected node data
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Node data (id, type, fields, layout etc.)
|
|
Sub UIThread_getNodeData(args) as Object
|
|
return getNodeData(m.currentNode, m.currentPath, Invalid)
|
|
End Sub
|
|
|
|
'=======================
|
|
' Tree View commands
|
|
'=======================
|
|
|
|
' UIThread_getItemList - RALE "getItemList" command handler. Returns node children and fields, by node path
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. List of node children and fields
|
|
Sub UIThread_getItemList(args) as Object
|
|
path = args["path"]
|
|
|
|
root = m.top.getScene()
|
|
node = RALE_getNodeByPath(root, path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
|
|
return getItemList(node, path)
|
|
End Sub
|
|
|
|
' UIThread_getNodeTree - RALE "getNodeTree" command handler. Returns children hierarchy by node path
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Node children hierarchy
|
|
Sub UIThread_getNodeTree(args) as Object
|
|
path = args["path"]
|
|
maxLevel = args["maxLevel"]
|
|
|
|
root = m.top.getScene()
|
|
node = RALE_getNodeByPath(root, path)
|
|
index = RALE_getNodeIndexByPath(path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
|
|
return getNodeTree(node, index, maxLevel)
|
|
End Sub
|
|
|
|
' UIThread_getNodeById - RALE "getNodeById" command handler. Returns node with requested id
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Found node data
|
|
Sub UIThread_getNodeById(args) as Object
|
|
path = args["path"]
|
|
id = args["id"]
|
|
|
|
if id = Invalid then return getError("id is required")
|
|
|
|
root = m.top.getScene()
|
|
rootNode = RALE_getNodeByPath(root, path)
|
|
if rootNode = Invalid then return getError("Invalid Path")
|
|
|
|
foundNode = getNodeById(rootNode, id)
|
|
foundPath = RALE_getNodePath(foundNode, root)
|
|
|
|
return getNodeData(foundNode, foundPath, root)
|
|
End Sub
|
|
|
|
' UIThread_getNodeByName - RALE "getNodeByName" command handler. Returns node with requested name
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Found node path
|
|
Sub UIThread_getNodeByName(args) as Object
|
|
path = args["path"]
|
|
name = args["name"]
|
|
|
|
if name = Invalid then return getError("name is required")
|
|
|
|
root = m.top.getScene()
|
|
rootNode = RALE_getNodeByPath(root, path)
|
|
if rootNode = Invalid then return getError("Invalid Path")
|
|
|
|
foundNode = getNodeByName(rootNode, name)
|
|
foundPath = RALE_getNodePath(foundNode, root)
|
|
|
|
return getNodeData(foundNode, foundPath, root)
|
|
End Sub
|
|
|
|
'=======================
|
|
' Children commands
|
|
'=======================
|
|
|
|
' UIThread_addChild - RALE "addChild" command handler. Adds new child to node by path (if no path adds to selected node)
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Contains node children hierarchy and index
|
|
Sub UIThread_addChild(args) as Object
|
|
childType = args["type"]
|
|
path = args["path"]
|
|
|
|
if not FW_IsString(childType) then return getError("childType is required")
|
|
|
|
index = FW_AsInteger(args["index"])
|
|
if index = 0 AND FW_AsString(args["index"]) <> "0" then index = Invalid
|
|
|
|
if path <> Invalid then
|
|
root = m.top.getScene()
|
|
node = RALE_getNodeByPath(root, path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
else
|
|
node = m.currentNode
|
|
path = m.currentPath
|
|
end if
|
|
|
|
result = addChild(node, childType, index)
|
|
if result.success = true then
|
|
index = RALE_getNodeIndexByPath(path)
|
|
return {
|
|
tree: getNodeTree(result.child, index, 50),
|
|
childindex: result.index
|
|
}
|
|
else
|
|
return result
|
|
end if
|
|
End Sub
|
|
|
|
' UIThread_removeChild - RALE "removeChild" command handler. Removes child from node by path (if no path removes from selected node)
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command
|
|
Sub UIThread_removeChild(args) as Object
|
|
index = FW_AsInteger(args["index"])
|
|
path = args["path"]
|
|
|
|
if index = 0 AND FW_AsString(args["index"]) <> "0" then return getError("index is required")
|
|
|
|
if path <> Invalid then
|
|
root = m.top.getScene()
|
|
node = RALE_getNodeByPath(root, path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
else
|
|
node = m.currentNode
|
|
path = m.currentPath
|
|
end if
|
|
|
|
return removeChild(node, index)
|
|
End Sub
|
|
|
|
' UIThread_moveChild - RALE "moveChild" command handler. Moves selected node child
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command
|
|
Sub UIThread_moveChild(args) as Object
|
|
fromIndex = FW_AsString(args["fromIndex"])
|
|
fromIndexInt = FW_AsInteger(fromIndex)
|
|
if fromIndexInt = 0 AND fromIndex <> "0" then return getError("fromIndex is required")
|
|
|
|
toIndex = FW_AsString(args["toIndex"])
|
|
toIndexInt = FW_AsInteger(toIndex)
|
|
if toIndexInt = 0 AND toIndex <> "0" then return getError("toIndex is required")
|
|
|
|
return moveChild(m.currentNode, fromIndexInt, toIndexInt)
|
|
End Sub
|
|
|
|
'=======================
|
|
' Fields commands
|
|
'=======================
|
|
|
|
' UIThread_setField - RALE "setField" command handler. Sets new value into node field (if the field doesn't exist creates it)
|
|
' @param {object} args - command arguments
|
|
' @return {array} - response of command. Node field list
|
|
Sub UIThread_setField(args) as Object
|
|
field = FW_AsString(args["field"])
|
|
fieldType = args["type"]
|
|
fieldValue = args["value"]
|
|
|
|
if field = "" then return getError("Field ID is required")
|
|
if RALE_convertToType(fieldValue, FW_AsString(fieldType)) = Invalid then return getError("Invalid Field Type or Value")
|
|
|
|
path = m.currentPath
|
|
nodeType = type(m.currentNode)
|
|
|
|
if nodeType = "roSGNode" then
|
|
setNodeField(m.currentNode, field, fieldValue, fieldType)
|
|
else
|
|
m.currentNode = setObjField(path, field, fieldValue, fieldType)
|
|
end if
|
|
|
|
return getFieldList(m.currentNode)
|
|
End Sub
|
|
|
|
' UIThread_removeField - RALE "removeField" command handler. Remove field from node by id
|
|
' @param {object} args - command arguments
|
|
' @return {array} - response of command. Node field list
|
|
Sub UIThread_removeField(args) as Object
|
|
field = args["field"]
|
|
if field = Invalid then return getError("Field ID is required")
|
|
|
|
node = m.currentNode
|
|
nodeType = type(node)
|
|
|
|
if nodeType = "roSGNode" then
|
|
node.removeField(field)
|
|
if node.hasField(field) then return getError("Field cannot be removed")
|
|
else if nodeType = "roAssociativeArray" or nodeType = "roArray" then
|
|
if nodeType = "roArray" then field = FW_AsInteger(field)
|
|
node.Delete(field)
|
|
|
|
inOwnerField = RALE_getNodeIndexByPath(m.currentPath)
|
|
if inOwnerField = Invalid then return getError("Invalid Path")
|
|
ownerPath = []
|
|
ownerPath.append(m.currentPath)
|
|
ownerPath.pop()
|
|
|
|
owner = setInParentNode(ownerPath, inOwnerField, node)
|
|
end if
|
|
|
|
return getFieldList(node)
|
|
End Sub
|
|
|
|
'=======================
|
|
' Focus commands
|
|
'=======================
|
|
|
|
' UIThread_setFocus - RALE "setFocus" command handler. Sets focus in node by path
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Status
|
|
Sub UIThread_setFocus(args) as Object
|
|
path = args["path"]
|
|
|
|
node = m.top.getScene()
|
|
node = RALE_getNodeByPath(node, path)
|
|
if node = Invalid then return getError("Invalid Path")
|
|
|
|
node.setFocus(true)
|
|
return { success: true }
|
|
End Sub
|
|
|
|
' UIThread_selectFocusedNode - RALE "selectFocusedNode" command handler. Select focused node
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Contains node path and data (id, type, fields, layout etc.)
|
|
Sub UIThread_selectFocusedNode(args) as Object
|
|
root = m.top.getScene()
|
|
node = getFocusedNodeObj(root)
|
|
if m.currentNode.IsSameNode(node) then
|
|
return {
|
|
path: m.currentPath,
|
|
node: getNodeData(node, m.currentPath, root)
|
|
}
|
|
else
|
|
path = RALE_getNodePath(node, root)
|
|
m.currentNode = node
|
|
m.currentPath = path
|
|
setSelectorView(node, type(node), path)
|
|
return {
|
|
path: path,
|
|
node: getNodeData(node, path, root)
|
|
}
|
|
end if
|
|
End Sub
|
|
|
|
'=======================
|
|
' Bounding Rect commands
|
|
'=======================
|
|
|
|
' UIThread_setBoundingRect - RALE "setBoundingRect" command handler. Sets properties into selected node layout
|
|
' @param {object} args - command arguments
|
|
' @return {object} - response of command. Node sceneBoundingRect
|
|
Sub UIThread_setBoundingRect(args) as Object
|
|
boundingRect = args["boundingrect"]
|
|
if boundingRect = Invalid then return getError("boundingrect is required")
|
|
|
|
node = m.currentNode
|
|
if type(node) <> "roSGNode" then return getError("Invalid Node Type")
|
|
currentBoundingRect = node.sceneBoundingRect()
|
|
|
|
if currentBoundingRect <> Invalid then
|
|
deltaX = 0
|
|
deltaY = 0
|
|
deltaWidth = 0
|
|
deltaHeight = 0
|
|
|
|
if boundingRect.x <> Invalid and boundingRect.y <> Invalid then
|
|
deltaX = currentBoundingRect.x - boundingRect.x
|
|
deltaY = currentBoundingRect.y - boundingRect.y
|
|
end if
|
|
|
|
if boundingRect.width <> Invalid and boundingRect.height <> Invalid then
|
|
deltaWidth = currentBoundingRect.width - boundingRect.width
|
|
deltaHeight = currentBoundingRect.height - boundingRect.height
|
|
end if
|
|
|
|
fields = {}
|
|
|
|
if node.hasField("translation") AND (deltaY <> 0 or deltaX <> 0) then
|
|
fields.translation = [node.translation[0] - deltaX, node.translation[1] - deltaY]
|
|
end if
|
|
|
|
if node.hasField("width") AND deltaWidth <> 0 then
|
|
if node.width = 0 AND deltaWidth > 0 then
|
|
fields.width = boundingRect.width
|
|
else
|
|
fields.width = node.width - deltaWidth
|
|
end if
|
|
end if
|
|
|
|
if node.hasField("height") AND deltaHeight <> 0 then
|
|
if node.height = 0 AND deltaHeight > 0 then
|
|
fields.height = boundingRect.height
|
|
else
|
|
fields.height = node.height - deltaHeight
|
|
end if
|
|
end if
|
|
|
|
node.setFields(fields)
|
|
end if
|
|
return node.sceneBoundingRect()
|
|
End Sub
|
|
|
|
'=======================
|
|
' Helpers functions
|
|
'=======================
|
|
|
|
' getLayout - Returns node layout fields (boundingRect, resolution, isMovable, isHeightResizable, isWidthResizable)
|
|
' @param {object} node - node
|
|
' @param {object} root - root of nodes (main scene)
|
|
' @return {object} - node layout
|
|
Sub getLayout(node, root) as Object
|
|
if not FW_IsSGNode(node) then return getError("Invalid Node Type")
|
|
|
|
if root = Invalid then root = m.top.getScene()
|
|
|
|
parent = node.getParent()
|
|
|
|
isWidthResizable = node.hasField("width")
|
|
isHeightResizable = node.hasField("height")
|
|
isMovable = false
|
|
|
|
if parent <> Invalid and not m.sceneBG.isSameNode(node) then
|
|
isMovable = node.hasField("translation") and parent.ParentSubtype("LayoutGroup") <> ""
|
|
end if
|
|
|
|
return {
|
|
isMovable : isMovable,
|
|
isHeightResizable : isHeightResizable,
|
|
isWidthResizable : isWidthResizable,
|
|
boundingRect : node.sceneBoundingRect(),
|
|
resolution : root.getField("currentDesignResolution")
|
|
}
|
|
End Sub
|
|
|
|
' getItemObj - Returns node object
|
|
' @param {object} item - node or filed
|
|
' @param {string} index - field id or child index
|
|
' @return {object} - node data object
|
|
Sub getItemObj(item, index) as Dynamic
|
|
itemType = type(item)
|
|
|
|
if itemType = "roSGNode" then
|
|
return {
|
|
index: index,
|
|
id: item.id,
|
|
childrenCount: item.getChildCount(),
|
|
subtype: item.subtype(),
|
|
type: itemType,
|
|
value: "{object}"
|
|
isExposed: FW_AsBoolean(item.isExternallyExposed)
|
|
}
|
|
else if itemType = "roArray" or itemType = "roAssociativeArray" then
|
|
return {
|
|
id: index,
|
|
type: itemType,
|
|
value: "{object}"
|
|
}
|
|
else
|
|
return {
|
|
id: index,
|
|
type: itemType,
|
|
value: FW_AsString(item)
|
|
}
|
|
end if
|
|
End Sub
|
|
|
|
' getFieldList - Returns node field list
|
|
' @param {object} node - node
|
|
' @return {array} - list of fields
|
|
Sub getFieldList(node) as Object
|
|
nodeType = type(node)
|
|
|
|
if nodeType = "roSGNode" then
|
|
fields = node.getFields()
|
|
else if nodeType = "roArray" or nodeType = "roAssociativeArray" then
|
|
fields = node
|
|
else
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
|
|
fieldList = {}
|
|
|
|
result = 0
|
|
if type(fields) = "roArray" then
|
|
count = fields.count() - 1
|
|
for i = 0 to count
|
|
id = i.ToStr()
|
|
fieldList[id] = { item: getItemObj(fields[i], i) }
|
|
end for
|
|
else
|
|
keys = fields.keys()
|
|
for each fieldId in keys
|
|
fieldList[fieldId] = { item: getItemObj(fields[fieldId], fieldId) }
|
|
if nodeType = "roSGNode" then fieldList[fieldId].item.fieldType = node.getFieldType(fieldId)
|
|
end for
|
|
end if
|
|
|
|
return fieldList
|
|
End Sub
|
|
|
|
' getChildList - Returns node children list
|
|
' @param {object} node - node
|
|
' @return {array} - list of children
|
|
Sub getChildList(node) as Object
|
|
nodeType = type(node)
|
|
|
|
if nodeType = "roSGNode" then
|
|
childList = []
|
|
children = node.getChildren(-1, 0)
|
|
count = children.count()
|
|
if count > 0 then
|
|
count--
|
|
for i = 0 to count
|
|
if children[i] <> Invalid then
|
|
childList[i] = { item: getItemObj(children[i], i) }
|
|
end if
|
|
end for
|
|
end if
|
|
return childList
|
|
else
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
End Sub
|
|
|
|
' getItemList - Returns node children list and node data
|
|
' @param {object} node - node
|
|
' @param {object} index - node index
|
|
' @return {object} - node data object and list of node children
|
|
Sub getItemList(node, index) as Object
|
|
item = { item: getItemObj(node, index) }
|
|
nodeType = type(node)
|
|
if nodeType = "roSGNode" then
|
|
item.childList = getChildList(node)
|
|
else
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
return item
|
|
End Sub
|
|
|
|
' getNodeTree - Goes through node children and returns node children hierarchy
|
|
' @param {object} node - node or filed
|
|
' @param {string} id - node index or filed id
|
|
' @return {array} - node children hierarchy
|
|
Sub getNodeTree(node, id, maxLevel) as Object
|
|
item = {
|
|
item: getItemObj(node, id),
|
|
childList: []
|
|
}
|
|
|
|
result = RALE_forEachChild(node, { maxLevel: maxLevel }, getNodeTreeCallback, { item: item })
|
|
|
|
if not result then
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
|
|
return item
|
|
End Sub
|
|
|
|
Sub getNodeTreeCallback(node, index, parentObj, childObj, storage) as Boolean
|
|
|
|
if parentObj.item = Invalid then
|
|
parentObj.item = storage.item
|
|
end if
|
|
|
|
childItem = {
|
|
item : getItemObj(node, index),
|
|
childList : []
|
|
}
|
|
|
|
parentObj.item.childlist[index] = childItem
|
|
|
|
if childObj <> Invalid then
|
|
childObj.item = childItem
|
|
end if
|
|
|
|
return true
|
|
End Sub
|
|
|
|
' getNodeById - Search for node by id
|
|
' @param {object} node - root node
|
|
' @param {string} id - node id
|
|
' @return {object} - found node
|
|
Sub getNodeById(rootNode, id) as Object
|
|
|
|
if rootNode.id = id then
|
|
return rootNode
|
|
end if
|
|
|
|
storage = {
|
|
node: Invalid,
|
|
id: id
|
|
}
|
|
|
|
result = RALE_forEachChild(rootNode, {}, getNodeByIdCallback, storage)
|
|
|
|
if not result then
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
|
|
return storage.node
|
|
End Sub
|
|
|
|
Sub getNodeByIdCallback(node, index, parentObj, childObj, storage) as Boolean
|
|
|
|
if node.id = storage.id then
|
|
storage.node = node
|
|
return false
|
|
end if
|
|
|
|
return true
|
|
End Sub
|
|
|
|
' getNodeByName - Search for node by name (subtype)
|
|
' @param {object} node - root node
|
|
' @param {string} name - node name (subtype)
|
|
' @return {object} - found node
|
|
Sub getNodeByName(rootNode, name) as Object
|
|
|
|
if rootNode.subtype() = name then
|
|
return rootNode
|
|
end if
|
|
|
|
storage = {
|
|
node: Invalid,
|
|
name: name
|
|
}
|
|
|
|
result = RALE_forEachChild(rootNode, {}, getNodeByNameCallback, storage)
|
|
|
|
if not result then
|
|
return getError("Invalid Node Type")
|
|
end if
|
|
|
|
return storage.node
|
|
End Sub
|
|
|
|
Sub getNodeByNameCallback(node, index, parentObj, childObj, storage) as Boolean
|
|
|
|
if node.subtype() = storage.name then
|
|
storage.node = node
|
|
return false
|
|
end if
|
|
|
|
return true
|
|
End Sub
|
|
|
|
' getNodeData - Returns node children hierarchy
|
|
' @param {object} node - node or filed
|
|
' @param {array} path - path to node
|
|
' @param {object} root - root of nodes (main scene)
|
|
' @return {object} - node data (item, fieldlist, layout)
|
|
Sub getNodeData(node, path, root) as Object
|
|
index = RALE_getNodeIndexByPath(path)
|
|
if index = Invalid then return getError("Invalid Path")
|
|
|
|
result = {
|
|
item: getItemObj(node, index),
|
|
fieldlist: getFieldList(node),
|
|
layout: getLayout(node, root)
|
|
}
|
|
if type(node) = "roSGNode" then result.childlist = getChildList(node)
|
|
|
|
return result
|
|
End Sub
|
|
|
|
' addChild - Adds child to node by type and index
|
|
' @param {object} node - parent node
|
|
' @param {string} childType - path to node
|
|
' @param {string} index - child index
|
|
' @return {object} - status
|
|
Sub addChild(node, childType, index) as Object
|
|
if not FW_IsSGNode(node) then return getError("Cannot Add Child. Invalid Node Type")
|
|
|
|
child = CreateObject("roSGNode", childType)
|
|
if not FW_IsSGNode(child) then return getError("Cannot Add Child. Invalid Component Type")
|
|
|
|
childCount = node.getChildCount()
|
|
if FW_IsInteger(index) and index < childCount then
|
|
node.insertChild(child, index)
|
|
else
|
|
index = childCount
|
|
node.appendChild(child)
|
|
end if
|
|
|
|
addedChild = node.getChild(index)
|
|
if type(addedChild) = "roSGNode" and addedChild.isSameNode(child) then
|
|
return { success: true, child: addedChild, index: index }
|
|
else
|
|
return getError("Cannot Add Child")
|
|
end if
|
|
End Sub
|
|
|
|
' removeChild - Removes child from node by index
|
|
' @param {object} node - parent node
|
|
' @param {string} index - child index
|
|
' @return {object} - status
|
|
Sub removeChild(node, index as Integer) as Object
|
|
if not FW_IsSGNode(node) then return getError("Invalid Node Type")
|
|
count = node.getChildCount()
|
|
if FW_IsSGNode(node.getChild(index)) then
|
|
node.removeChildIndex(index)
|
|
if node.getChildCount() < count then return { success: true }
|
|
return getError("Node cannot be removed")
|
|
else
|
|
return getError("No child with this index")
|
|
end if
|
|
End Sub
|
|
|
|
' moveChild - Moves node child by index to another position
|
|
' @param {object} node - parent node
|
|
' @param {string} fromIndex - current child index
|
|
' @param {string} toIndex - index where you want to move
|
|
' @return {object} - status
|
|
Sub moveChild(node, fromIndex, toIndex) as Object
|
|
if not FW_IsSGNode(node) then return getError("Invalid Node Type")
|
|
|
|
if fromIndex >= 0 AND toIndex >= 0
|
|
child = node.getChild(fromIndex)
|
|
if child <> Invalid then
|
|
node.removeChildIndex(fromIndex)
|
|
if toIndex > fromIndex then toIndex--
|
|
node.insertChild(child, toIndex)
|
|
return { success: true }
|
|
else
|
|
return getError("No child with this index")
|
|
end if
|
|
else
|
|
return getError("fromIndex and toIndex must be positive integer")
|
|
end if
|
|
End Sub
|
|
|
|
' setSelectorView - Shows selector (live) view for node
|
|
' @param {object} node - node
|
|
' @param {string} nodeType - type of node
|
|
' @param {array} nodePath - path to node
|
|
' @return {object} - status
|
|
Function setSelectorView(node, nodeType, nodePath) as Object
|
|
if m.selectorView <> Invalid then
|
|
if m.showSelectorView and nodeType = "roSGNode" and nodePath.count() > 0 then
|
|
m.selectorView.attachedView = node
|
|
else
|
|
m.selectorView.attachedView = Invalid
|
|
end if
|
|
end if
|
|
End Function
|
|
|
|
' setNodeField - Sets field into node
|
|
' @param {object} node - node
|
|
' @param {string} field - field id
|
|
' @param {dynamic} value - field value
|
|
' @param {string} fieldType - field type
|
|
Sub setNodeField(node, field, value, fieldType) as Object
|
|
fields = {}
|
|
if fieldType = Invalid then
|
|
fields[field] = value
|
|
if node.hasField(field) then
|
|
node.setFields(fields)
|
|
else
|
|
node.addFields(fields)
|
|
end if
|
|
else
|
|
fields[field] = RALE_convertToType(value, fieldType)
|
|
if node.hasField(field) and node.getFieldType(field) <> fieldType then
|
|
node.removeField(field)
|
|
end if
|
|
|
|
if not node.hasField(field) then
|
|
node.addField(field, RALE_parseType(fieldType), false)
|
|
end if
|
|
node.setFields(fields)
|
|
end if
|
|
End Sub
|
|
|
|
' setObjField - Sets field into AssociativeArray
|
|
' @param {array} parentPath - node
|
|
' @param {string} field - field id
|
|
' @param {dynamic} value - field value
|
|
' @param {string} fieldType - field type
|
|
' @return {object} - status
|
|
Sub setObjField(parentPath, field, value, fieldType) as Object
|
|
if fieldType <> Invalid then
|
|
value = RALE_convertToType(value, fieldType)
|
|
end if
|
|
return setInParentNode(parentPath, field, value)
|
|
End Sub
|
|
|
|
' setInParentNode - Sets field into parent node
|
|
' @param {array} path - path to field
|
|
' @param {string} field - field id
|
|
' @param {dynamic} value - field value
|
|
' @return {object} - parent node
|
|
Function setInParentNode(path, field, value)
|
|
root = m.top.getScene()
|
|
parentPath = []
|
|
parentPath.append(path)
|
|
nodeList = RALE_getNodeListByPath(root, path)
|
|
if nodeList = Invalid then return getError("Invalid Path")
|
|
|
|
index = nodeList.count() - 1
|
|
parent = nodeList[index]
|
|
if type(parent) = "roSGNode" then
|
|
setNodeField(parent, field, value, Invalid)
|
|
return parent
|
|
end if
|
|
|
|
while type(parent) <> "roSGNode"
|
|
if type(parent) = "roArray" then
|
|
field = FW_AsInteger(field)
|
|
if field > parent.count() then
|
|
field = parent.count()
|
|
end if
|
|
parent[field] = value
|
|
else
|
|
parent[field] = value
|
|
end if
|
|
value = parent
|
|
index--
|
|
field = path[index].field
|
|
parent = nodeList[index]
|
|
parentPath.pop()
|
|
end while
|
|
|
|
parent = RALE_getNodeByPath(root, parentPath)
|
|
setNodeField(parent, field, value, Invalid)
|
|
return RALE_getNodeByPath(root, path)
|
|
End Function
|
|
|
|
' setFocus - Focus node
|
|
' @param {object} node - node
|
|
Sub setFocus(node) as Object
|
|
if not FW_IsSGNode(node) then return getError("Invalid Node Type")
|
|
node.setFocus(true)
|
|
End Sub
|
|
|
|
' getFocusedNodeObj - Returns focused node
|
|
' @param {object} root - root
|
|
' @param {object} maxDeep - search depth
|
|
' @return {object} - focused node
|
|
Function getFocusedNodeObj(root, maxDeep = 25) as Object
|
|
node = root
|
|
focusedChild = node.focusedChild
|
|
while maxDeep > 0 AND focusedChild <> Invalid AND not node.isSameNode(focusedChild)
|
|
node = focusedChild
|
|
focusedChild = node.focusedChild
|
|
maxDeep--
|
|
end while
|
|
return node
|
|
End Function
|
|
|
|
' getError - Returns error object
|
|
' @param {string} message - error message
|
|
Function getError(message as String) as Object
|
|
return { error: { message: message } }
|
|
End Function
|
|
|
|
|
|
' @desc TrackerTask init function
|
|
Sub init()
|
|
m.top.functionName = "tracker"
|
|
m.top.control = "RUN"
|
|
|
|
m.config = RALE_Config()
|
|
m.sceneBG = m.top.GetScene().getChild(0)
|
|
m.raleVersion = "1.7.11"
|
|
End Sub
|
|
|
|
' tracker - TrackerTask run function
|
|
Sub tracker()
|
|
appInfo = CreateObject("roAppInfo")
|
|
if not appInfo.IsDev() then return
|
|
|
|
?"tracker Run"
|
|
handlersMap = getCommandMap()
|
|
buffer = CreateObject("roByteArray")
|
|
buffer[m.config.bufferSize] = 0
|
|
messagePort = CreateObject("roMessagePort")
|
|
addr = CreateObject("roSocketAddress")
|
|
|
|
inputPort = CreateObject("roMessagePort")
|
|
inputObj = CreateObject("roInput")
|
|
inputObj.SetMessagePort(inputPort)
|
|
|
|
while True
|
|
port = 0
|
|
msg = wait(0, inputPort)
|
|
if type(msg) = "roInputEvent"
|
|
if msg.IsInput()
|
|
info = msg.GetInfo()
|
|
if type(info) = "roAssociativeArray" and info.rale <> Invalid then
|
|
port = FW_AsInteger(info.port)
|
|
end if
|
|
end if
|
|
end if
|
|
if port > m.config.minSocketPort and port < m.config.maxSocketPort then
|
|
socketConnection(addr, messagePort, port, buffer, handlersMap, m.config)
|
|
end if
|
|
end while
|
|
|
|
End Sub
|
|
|
|
' socketConnection - Starts socket connection. Keep alive while connection won't be closed
|
|
' @param {object} addr - roSocketAddress
|
|
' @param {object} messagePort - roMessagePort
|
|
' @param {number} port - socket connection port
|
|
' @param {array} buffer - buffer for socket packets
|
|
' @param {object} handlersMap - map that contains all RALE commands handlers
|
|
' @param {object} config - configuration constants
|
|
' @return {string} - connection status
|
|
Sub socketConnection(addr, messagePort, port, buffer, handlersMap, config) as String
|
|
connections = {}
|
|
appManager = createObject("roAppManager")
|
|
screensaverTimer = CreateObject("roTimespan")
|
|
screensaverTimer.Mark()
|
|
|
|
addr.setPort(port)
|
|
|
|
tcpListen = CreateObject("roStreamSocket")
|
|
tcpListen.setMessagePort(messagePort)
|
|
tcpListen.setAddress(addr)
|
|
tcpListen.notifyReadable(true)
|
|
tcpListen.listen(4)
|
|
|
|
wasConnected = false
|
|
|
|
while True
|
|
|
|
if not wasConnected then
|
|
event = wait(3000, messagePort)
|
|
if event = Invalid then
|
|
tcpListen.close()
|
|
return "connection timeout"
|
|
end if
|
|
else
|
|
event = wait(config.commandTimeout, messagePort)
|
|
end if
|
|
|
|
' Resets the screensaver timer
|
|
if screensaverTimer.TotalMilliseconds() > config.screensaverResetTimeout then
|
|
screensaverTimer.Mark()
|
|
appManager.UpdateLastKeyPressTime()
|
|
end if
|
|
|
|
' ? type(event)
|
|
if type(event) = "roSocketEvent"
|
|
wasConnected = true
|
|
changedID = event.getSocketID()
|
|
if changedID = tcpListen.getID() and tcpListen.isReadable()
|
|
' New
|
|
newConnection = tcpListen.accept()
|
|
if newConnection = Invalid
|
|
print "accept failed"
|
|
else
|
|
print "accepted new connection " newConnection.getID()
|
|
newConnection.notifyReadable(true)
|
|
newConnection.setMessagePort(messagePort)
|
|
connections[Stri(newConnection.getID())] = newConnection
|
|
end if
|
|
else
|
|
' Activity on an open connection
|
|
connection = connections[Stri(changedID)]
|
|
closed = False
|
|
if connection.isReadable()
|
|
received = connection.receive(buffer, 0, 1024)
|
|
if received > 0
|
|
timer = CreateObject("roTimespan")
|
|
timer.Mark()
|
|
str = buffer.ToAsciiString().Left(received)
|
|
request = ParseJson(str)
|
|
buffer = CreateObject("roByteArray")
|
|
buffer[1024] = 0
|
|
|
|
if request <> Invalid then
|
|
response = {}
|
|
if request["command"] <> Invalid then
|
|
? "handling : " request["command"]
|
|
handler = handlersMap[request["command"]]
|
|
if handler <> Invalid then
|
|
response = callCommand(handler, request["args"])
|
|
else
|
|
response = getError("No such command")
|
|
end if
|
|
end if
|
|
id = request.uuid
|
|
idLen = FW_AsString(Len(id))
|
|
json = FormatJson(response)
|
|
res = "[start][uuid:" + idLen + "]" + id + json + "[end]"
|
|
|
|
resList = RALE_splitStringByLength(res, 3000)
|
|
count = resList.count() - 1
|
|
for i = 0 to count
|
|
connection.SendStr(resList[i])
|
|
sleep(20)
|
|
end for
|
|
|
|
? "command handled in : " timer.TotalMilliseconds()
|
|
end if
|
|
else if received=0 ' client closed
|
|
closed = True
|
|
end if
|
|
end if
|
|
if closed or not connection.eOK()
|
|
connection.close()
|
|
connections.delete(Stri(changedID))
|
|
exit while
|
|
end if
|
|
end if
|
|
end if
|
|
end while
|
|
|
|
tcpListen.close()
|
|
for each id in connections
|
|
connections[id].close()
|
|
end for
|
|
|
|
return "connection closed"
|
|
End Sub
|
|
|
|
'IMPORTS=
|
|
'=====================
|
|
' Types
|
|
'=====================
|
|
|
|
'*************************************************
|
|
' FW_IsXmlElement - check if value contains XMLElement interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains XMLElement interface, else return false
|
|
'*************************************************
|
|
Function FW_IsXmlElement(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifXMLElement") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsFunction - check if value contains Function interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains Function interface, else return false
|
|
'*************************************************
|
|
Function FW_IsFunction(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifFunction") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsBoolean - check if value contains Boolean interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains Boolean interface, else return false
|
|
'*************************************************
|
|
Function FW_IsBoolean(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifBoolean") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsInteger - check if value type equals Integer
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value type equals Integer, else return false
|
|
'*************************************************
|
|
Function FW_IsInteger(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifInt") <> invalid And (Type(value) = "roInt" Or Type(value) = "roInteger" Or Type(value) = "Integer")
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsFloat - check if value contains Float interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains Float interface, else return false
|
|
'*************************************************
|
|
Function FW_IsFloat(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifFloat") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsDouble - check if value contains Double interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains Double interface, else return false
|
|
'*************************************************
|
|
Function FW_IsDouble(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifDouble") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsLongInteger - check if value contains LongInteger interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains LongInteger interface, else return false
|
|
'*************************************************
|
|
Function FW_IsLongInteger(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifLongInt") <> invalid
|
|
End Function
|
|
|
|
|
|
'*************************************************
|
|
' FW_IsNumber - check if value contains LongInteger or Integer or Double or Float interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value is number, else return false
|
|
'*************************************************
|
|
Function FW_IsNumber(value As Dynamic) As Boolean
|
|
Return FW_IsLongInteger(value) or FW_IsDouble(value) or FW_IsInteger(value) or FW_IsFloat(value)
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsList - check if value contains List interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains List interface, else return false
|
|
'*************************************************
|
|
Function FW_IsList(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifList") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsArray - check if value contains Array interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains Array interface, else return false
|
|
'*************************************************
|
|
Function FW_IsArray(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifArray") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsAssociativeArray - check if value contains AssociativeArray interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains AssociativeArray interface, else return false
|
|
'*************************************************
|
|
Function FW_IsAssociativeArray(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifAssociativeArray") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsSGNode - check if value contains SGNodeChildren interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains SGNodeChildren interface, else return false
|
|
'*************************************************
|
|
Function FW_IsSGNode(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifSGNodeChildren") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsString - check if value contains String interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains String interface, else return false
|
|
'*************************************************
|
|
Function FW_IsString(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And GetInterface(value, "ifString") <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsNotEmptyString - check if value contains String interface and length more 0
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains String interface and length more 0, else return false
|
|
'*************************************************
|
|
Function FW_IsNotEmptyString(value As Dynamic) As Boolean
|
|
Return FW_IsString(value) and len(value) > 0
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsDateTime - check if value contains DateTime interface
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value contains DateTime interface, else return false
|
|
'*************************************************
|
|
Function FW_IsDateTime(value As Dynamic) As Boolean
|
|
Return FW_IsValid(value) And (GetInterface(value, "ifDateTime") <> invalid Or Type(value) = "roDateTime")
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_IsValid - check if value initialized and not equal invalid
|
|
' @param value As Dynamic
|
|
' @return As Boolean - true if value initialized and not equal invalid, else return false
|
|
'*************************************************
|
|
Function FW_IsValid(value As Dynamic) As Boolean
|
|
Return Type(value) <> "<uninitialized>" And value <> invalid
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_ValidStr - return value if his contains String interface else return empty string
|
|
' @param value As Object
|
|
' @return As String - value if his contains String interface else return empty string
|
|
'*************************************************
|
|
Function FW_ValidStr(obj As Object) As String
|
|
if obj <> invalid and GetInterface(obj, "ifString") <> invalid
|
|
return obj
|
|
else
|
|
return ""
|
|
endif
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsString - convert input to String if this possible, else return empty string
|
|
' @param input As Dynamic
|
|
' @return As String - return converted string
|
|
'*************************************************
|
|
Function FW_AsString(input As Dynamic) As String
|
|
If FW_IsValid(input) = False Then
|
|
Return ""
|
|
Else If FW_IsString(input) Then
|
|
Return input
|
|
Else If FW_IsInteger(input) or FW_IsLongInteger(input) or FW_IsBoolean(input)Then
|
|
Return input.ToStr()
|
|
Else If FW_IsFloat(input) or FW_IsDouble(input) Then
|
|
Return Str(input).Trim()
|
|
Else
|
|
Return ""
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsInteger - convert input to Integer if this possible, else return 0
|
|
' @param input As Dynamic
|
|
' @return As Integer - return converted Integer
|
|
'*************************************************
|
|
Function FW_AsInteger(input As Dynamic) As Integer
|
|
If FW_IsValid(input) = False Then
|
|
Return 0
|
|
Else If FW_IsString(input) Then
|
|
Return input.ToInt()
|
|
Else If FW_IsInteger(input) Then
|
|
Return input
|
|
Else If FW_IsFloat(input) or FW_IsDouble(input) or FW_IsLongInteger(input) Then
|
|
Return Int(input)
|
|
Else
|
|
Return 0
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsLongInteger - convert input to LongInteger if this possible, else return 0
|
|
' @param input As Dynamic
|
|
' @return As Integer - return converted LongInteger
|
|
'*************************************************
|
|
Function FW_AsLongInteger(input As Dynamic) As LongInteger
|
|
If FW_IsValid(input) = False Then
|
|
Return 0
|
|
Else If FW_IsString(input) Then
|
|
Return FW_AsInteger(input)
|
|
Else If FW_IsLongInteger(input) or FW_IsFloat(input) or FW_IsDouble(input) or FW_IsInteger(input) Then
|
|
Return input
|
|
Else
|
|
Return 0
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsFloat - convert input to Float if this possible, else return 0.0
|
|
' @param input As Dynamic
|
|
' @return As Float - return converted Float
|
|
'*************************************************
|
|
Function FW_AsFloat(input As Dynamic) As Float
|
|
If FW_IsValid(input) = False Then
|
|
Return 0.0
|
|
Else If FW_IsString(input) Then
|
|
Return input.ToFloat()
|
|
Else If FW_IsInteger(input) Then
|
|
Return (input / 1)
|
|
Else If FW_IsFloat(input) or FW_IsDouble(input) or FW_IsLongInteger(input) Then
|
|
Return input
|
|
Else
|
|
Return 0.0
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsDouble - convert input to Double if this possible, else return 0.0
|
|
' @param input As Dynamic
|
|
' @return As Float - return converted Double
|
|
'*************************************************
|
|
Function FW_AsDouble(input As Dynamic) As Double
|
|
If FW_IsValid(input) = False Then
|
|
Return 0.0
|
|
Else If FW_IsString(input) Then
|
|
Return FW_AsFloat(input)
|
|
Else If FW_IsInteger(input) or FW_IsLongInteger(input) or FW_IsFloat(input) or FW_IsDouble(input) Then
|
|
Return input
|
|
Else
|
|
Return 0.0
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsBoolean - convert input to Boolean if this possible, else return False
|
|
' @param input As Dynamic
|
|
' @return As Boolean
|
|
'*************************************************
|
|
Function FW_AsBoolean(input As Dynamic) As Boolean
|
|
If FW_IsValid(input) = False Then
|
|
Return False
|
|
Else If FW_IsString(input) Then
|
|
Return LCase(input) = "true"
|
|
Else If FW_IsInteger(input) Or FW_IsFloat(input) Then
|
|
Return input <> 0
|
|
Else If FW_IsBoolean(input) Then
|
|
Return input
|
|
Else
|
|
Return False
|
|
End If
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_AsArray - if type of value equals array return value, else return array with one element [value]
|
|
' @param value As Object
|
|
' @return As Object - roArray
|
|
'*************************************************
|
|
Function FW_AsArray(value As Object) As Object
|
|
If FW_IsValid(value)
|
|
If Not FW_IsArray(value) Then
|
|
Return [value]
|
|
Else
|
|
Return value
|
|
End If
|
|
End If
|
|
Return []
|
|
End Function
|
|
|
|
'*************************************************
|
|
' FW_ValidAA - check if obj contains all keys
|
|
' @param obj As Object - roAssociativeArray
|
|
' @param keys as Object - roArray of keys(string) to check
|
|
' @param delim as String - key delimiter (default = ".")
|
|
' @return As Boolean - return true if type of obj equals AssociativeArray and obj contains all keys, else return false
|
|
'*************************************************
|
|
Function FW_ValidAA(obj As Object, keys as Object, delim = "." as String) as Boolean
|
|
'All keys on level 0
|
|
if not FW_IsAssociativeArray(obj) or not FW_IsNotEmptyString(delim) or not FW_isArray(keys) then
|
|
return false
|
|
end if
|
|
for each key in Keys
|
|
subKeys = FW_Split(key, delim)
|
|
aa_check = obj
|
|
'go down the hierarchy key.subkey.subsubkey...
|
|
for each subkey in subKeys
|
|
if FW_IsAssociativeArray(aa_check) and aa_check[subkey] <> invalid then
|
|
aa_check = aa_check[subkey]
|
|
else
|
|
print "Key::"; key
|
|
print "subkey::"; subkey
|
|
printAA(obj)
|
|
return false
|
|
|
|
end if
|
|
end for
|
|
|
|
end for
|
|
return true
|
|
end Function
|
|
|
|
'*************************************************
|
|
' FW_GetSubElement - check if obj contains subElementTree element and return him
|
|
' @param element as Dynamic - roAssociativeArray
|
|
' @param subElementTree as Dynamic - String keys tree
|
|
' @param delim as String - key delimiter (default = ".")
|
|
' @return As Dynamic - if exist obj[subElementTree] value else invalid
|
|
'*************************************************
|
|
function FW_GetSubElement(element as Dynamic, subElementTree as Dynamic, delim = "." as String) as Dynamic
|
|
if FW_IsValid(element) = false or FW_IsValid(subElementTree) = false then
|
|
return invalid
|
|
end if
|
|
|
|
subElementTreeArray = []
|
|
result = element
|
|
|
|
if FW_IsNotEmptyString(subElementTree) and FW_IsNotEmptyString(delim) then
|
|
subElementTreeArray = FW_Split(subElementTree, delim)
|
|
else if FW_IsArray(subElementTree) then
|
|
subElementTreeArray = subElementTree
|
|
else
|
|
result = invalid
|
|
end if
|
|
|
|
for each field in subElementTreeArray
|
|
if FW_IsSGNode(result) then
|
|
key = FW_AsString(field)
|
|
if result.HasField(key) then
|
|
result = result.GetField(key)
|
|
else
|
|
index = FW_AsInteger(field)
|
|
if (index = 0 and key <> "0") or index < 0 or index >= result.GetChildCount() then
|
|
result = invalid
|
|
exit for
|
|
end if
|
|
result = result.GetChild(index)
|
|
end if
|
|
else if FW_IsAssociativeArray(result) then
|
|
result = result.LookupCI(FW_AsString(field)) 'use case-insensitive lookup for AAs
|
|
else if FW_IsArray(result) then
|
|
index = FW_AsInteger(field)
|
|
if (index = 0 and FW_AsString(field) <> "0") or index < 0 or index >= result.Count() then 'index is not an integer or out of range?
|
|
result = invalid
|
|
exit for
|
|
end if
|
|
result = result[index]
|
|
else
|
|
result = invalid
|
|
exit for
|
|
end if
|
|
end for
|
|
|
|
return result
|
|
end function
|
|
|
|
' RALE_parseType - Parse type name to brs type
|
|
' @param {string} _type - type
|
|
' @return {string} - brs type
|
|
Function RALE_parseType(_type as String) as String
|
|
_type = LCase(_type)
|
|
convertMap = {
|
|
"rointeger" : "integer",
|
|
"roint" : "integer",
|
|
"int" : "integer",
|
|
"num" : "integer",
|
|
"number" : "integer",
|
|
|
|
"rofloat" : "float",
|
|
|
|
"rostring" : "string",
|
|
"text" : "string",
|
|
"str" : "string",
|
|
|
|
"roboolean" : "bool",
|
|
"boolean" : "bool",
|
|
|
|
"rosgnode" : "node",
|
|
|
|
"roarray" : "array",
|
|
"array" : "array",
|
|
"arr" : "array",
|
|
|
|
"object" : "assocarray",
|
|
"associativearray" : "assocarray",
|
|
"roassociativearray" : "assocarray"
|
|
}
|
|
if convertMap[_type] <> Invalid then return convertMap[_type]
|
|
return _type
|
|
End function
|
|
|
|
' RALE_convertToType - Convert variable to type
|
|
' @param {dynamic} value - variable value
|
|
' @param {string} _type - type to which you want to convert
|
|
' @return {dynamic} - new variable value
|
|
Function RALE_convertToType(value as Dynamic, _type as String) as Dynamic
|
|
_type = RALE_parseType(_type)
|
|
|
|
convertMap = {
|
|
"integer" : FW_AsInteger,
|
|
"float" : FW_AsFloat,
|
|
"bool" : FW_AsBoolean,
|
|
"string" : FW_AsString,
|
|
"array" : FW_AsArray,
|
|
}
|
|
|
|
if _type = "assocarray" and type(value) <> "roAssociativeArray" then
|
|
value = CreateObject("roAssociativeArray")
|
|
end if
|
|
if _type = "array" and type(value) <> "roArray" then
|
|
value = FW_AsString(value).split(",")
|
|
end if
|
|
if _type = "node" then
|
|
value = CreateObject("roSGNode", FW_AsString(value))
|
|
end if
|
|
|
|
if convertMap[_type] <> Invalid then
|
|
return convertMap[_type](value)
|
|
end if
|
|
return value
|
|
End function
|
|
|
|
' RALE_getNodeByItem - Returns node field or child by item data
|
|
' @param {dynamic} item - item data
|
|
' @param {dynamic} node - type to which you want to convert
|
|
' @return {dynamic} - node field or child
|
|
Function RALE_getNodeByItem(item as Dynamic, node as Dynamic) as Dynamic
|
|
itemType = type(item)
|
|
if itemType <> "roAssociativeArray" then return Invalid
|
|
|
|
nodeType = type(node)
|
|
if nodeType <> "roSGNode" and nodeType <> "roArray" and nodeType <> "roAssociativeArray" then
|
|
return Invalid
|
|
end if
|
|
|
|
if nodeType = "roSGNode" and item.child <> Invalid then
|
|
index = FW_AsInteger(item.child)
|
|
if index = 0 and FW_AsString(item.child) <> "0" then return Invalid
|
|
|
|
return node.getChild(index)
|
|
else if item.field <> Invalid then
|
|
key = item.field
|
|
if nodeType = "roSGNode" then
|
|
if node.hasField(key) then
|
|
return node.getField(key)
|
|
else
|
|
return Invalid
|
|
end if
|
|
else
|
|
key = item.field
|
|
if nodeType = "roArray" then
|
|
key = FW_AsInteger(key)
|
|
if key = 0 and FW_AsString(item.field) <> "0" then return Invalid
|
|
end if
|
|
|
|
return node[key]
|
|
end if
|
|
else
|
|
return Invalid
|
|
end if
|
|
End function
|
|
|
|
' RALE_getNodeByPath - Returns node by path
|
|
' @param {object} root - root of nodes (main scene)
|
|
' @param {array} path - path to node (for example [{ child: 1 }, { field: "fieldId" }])
|
|
' @return {dynamic} - node or Invalid (if no node by this path)
|
|
Function RALE_getNodeByPath(root as Dynamic, path as Object) as Dynamic
|
|
node = root
|
|
|
|
if type(path) <> "roArray" then return Invalid
|
|
|
|
for each item in path
|
|
node = RALE_getNodeByItem(item, node)
|
|
if node = Invalid then return Invalid
|
|
end for
|
|
|
|
return node
|
|
End function
|
|
|
|
' RALE_getNodeIndex - Returns node index
|
|
' @param {object} node - node
|
|
' @param {object} parent - node parent
|
|
' @return {integer} - node index
|
|
Function RALE_getNodeIndex(node, parent) as Integer
|
|
for i = 0 to parent.getchildCount() - 1
|
|
if parent.getChild(i).isSameNode(node) then return i
|
|
end for
|
|
return -1
|
|
End Function
|
|
|
|
' RALE_getNodePath - Returns node path
|
|
' @param {object} node - node
|
|
' @param {object} root - root
|
|
' @return {array} - node path
|
|
Function RALE_getNodePath(node, root) as Object
|
|
path = []
|
|
|
|
if node <> Invalid and root <> Invalid then
|
|
parent = node.getParent()
|
|
while parent <> Invalid
|
|
index = RALE_getNodeIndex(node, parent)
|
|
if index = -1 then exit while
|
|
|
|
node = parent
|
|
parent = node.getParent()
|
|
|
|
path.unshift({ child: index })
|
|
|
|
if root.isSameNode(node) then exit while
|
|
end while
|
|
end if
|
|
return path
|
|
End Function
|
|
|
|
' RALE_getNodeListByPath - Returns node by path
|
|
' @param {object} root - root of nodes (main scene)
|
|
' @param {array} path - path to node (for example [{ child: 1 }, { field: "fieldId" }])
|
|
' @return {dynamic} - list of nodes (parent nodes and selected one) or Invalid (if no node by this path)
|
|
Function RALE_getNodeListByPath(root as Dynamic, path as Object) as Dynamic
|
|
node = root
|
|
nodeList = [node]
|
|
|
|
if type(path) <> "roArray" then return Invalid
|
|
|
|
for each item in path
|
|
node = RALE_getNodeByItem(item, node)
|
|
if node = Invalid then return Invalid
|
|
nodeList.push(node)
|
|
end for
|
|
|
|
return nodeList
|
|
End function
|
|
|
|
' RALE_getNodeIndexByPath - Returns node index or id by path
|
|
' @param {array} path - path to node (for example [{ child: 1 }, { field: "fieldId" }])
|
|
' @return {dynamic} - node index or id or Invalid (if no node by this path)
|
|
Function RALE_getNodeIndexByPath(path) as Dynamic
|
|
if type(path) <> "roArray" then return Invalid
|
|
|
|
length = path.count()
|
|
if length = 0 then return ""
|
|
|
|
index = path[length - 1]
|
|
|
|
if type(index) <> "roAssociativeArray" then return Invalid
|
|
|
|
if index.child <> Invalid then
|
|
index = index.child
|
|
else if index.field <> Invalid then
|
|
index = index.field
|
|
else
|
|
return Invalid
|
|
end if
|
|
|
|
return index
|
|
End function
|
|
|
|
' RALE_splitStringByLength - Splits string on parts and store in array
|
|
' @param {string} str - string which will be splitted
|
|
' @param {integer} length - max part langth
|
|
' @return {array} - splitted string
|
|
Function RALE_splitStringByLength(str, length) as Dynamic
|
|
list = []
|
|
strLength = str.len()
|
|
currentPosition = 0
|
|
|
|
while currentPosition < strLength
|
|
list.push(str.mid(currentPosition, length))
|
|
currentPosition = currentPosition + length
|
|
end while
|
|
|
|
return list
|
|
End function
|
|
|
|
|
|
|
|
' RALE_forEachNode - Goes through all the children and call the callback function
|
|
' @param {object} node - root node
|
|
' @param {object} options - options
|
|
' @param {function} callback - callback function that will be called for each node
|
|
Function RALE_forEachChild(node, options, callback, storage) as Dynamic
|
|
nodeType = type(node)
|
|
maxLevel = 50
|
|
|
|
if FW_IsInteger(options.maxLevel) then
|
|
maxLevel = options.maxLevel
|
|
end if
|
|
|
|
if nodeType = "roSGNode" then
|
|
level = 0
|
|
stateStack = []
|
|
stateObj = {
|
|
index : 0
|
|
node : node
|
|
}
|
|
|
|
childCount = node.getchildcount()
|
|
while true
|
|
|
|
if childCount > stateObj.index then
|
|
childIndex = stateObj.index
|
|
childNode = node.getchild(childIndex)
|
|
|
|
stateObj.index++
|
|
|
|
if childNode <> invalid then
|
|
childCountTmp = childNode.getchildcount()
|
|
|
|
parentObj = stateObj
|
|
childObj = Invalid
|
|
|
|
if childCountTmp > 0 and level < maxLevel then
|
|
childCount = childCountTmp
|
|
stateStack.push(stateObj)
|
|
level++
|
|
|
|
stateObj = {
|
|
index : 0
|
|
node : childNode
|
|
}
|
|
childObj = stateObj
|
|
|
|
node = childNode
|
|
end if
|
|
|
|
result = callback(childNode, childIndex, parentObj, childObj, storage)
|
|
|
|
if not result then
|
|
exit while
|
|
end if
|
|
end if
|
|
else if level > 0 then
|
|
stateObj = stateStack.pop()
|
|
level--
|
|
node = stateObj.node
|
|
childCount = stateObj.node.getchildcount()
|
|
else
|
|
exit while
|
|
end if
|
|
end while
|
|
else
|
|
return false
|
|
end if
|
|
|
|
return true
|
|
End function
|
|
|
|
]]>
|
|
</script>
|
|
</component>
|