So i have been dabbling in making RSG palatable to humans and here is what i mixed up, still a work in progress. This is a re-make of the
EventObserverExample and there is
no XML and
no subclassing (i.e. no need to create a custom <component/> just to do a trivial job!). All the custom code is BrightScript and main.brs goes like this:
sub main():
screen = createObject("roSGScreen")
port = createObject("roMessagePort")
screen.setMessagePort(port)
scene = screen.createScene("_scene")
screen.show()
scene.setFocus(true)
scene.backgroundURI = "pkg:/images/rsgde_bg_hd.jpg"
scene._ingest = {__: [
{ _: "Rectangle", id: "textRectangle"
width: 640, height: 60
color: "0x10101000"
backgroundURI: "pkg:/images/rsgde_bg_hd.jpg"
__: { _: "Label", id: "movingLabel"
width: 280, height: 60
horizAlign: "center", vertAlign: "center"
text: "All The Best Videos!"
}
}
{ _: "Animation", id: "scrollbackAnimation"
duration: 10
repeat: true
easeFunction: "linear"
__: { _: "Vector2DFieldInterpolator"
fieldToInterp: "movingLabel.translation"
key: [0.0, 0.5, 1.0]
keyValue: [[0.0, 0.0], [360.0, 0.0], [0.0, 0.0]]
}
}
{ _: "Timer", id: "textTimer"
duration: 5
repeat: true
}
]}
scene._ingest = {_m: {
defaulttext: "All The Best Videos!"
alternatetext: "All The Time!!!"
}}
scene._ingest = {_exec: [
" _observeField(m.texttimer, ""fire"", function(msg): "
" lbl = m.movingLabel "
" if lbl.text = m.defaultText: "
" lbl.text = m.alternateText "
" else: "
" lbl.text = m.defaultText "
" end if "
" end function) "
]}
rect = scene.textRectangle.boundingRect()
centerx = (1280 - rect.width) / 2
centery = (720 - rect.height) / 2
scene.textRectangle.translation = [centerx, centery]
scene.textTimer.control = "start"
scene.scrollbackAnimation.control = "start"
while true:
msg = wait(0, port)
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then exit while
end while
end sub
Yes, this code
works as shown - not a hypothetical construct anymore. The "secret sauce" is in the _scene component, a thin veneer (couple of screens) that extends Scene with _ingest "executor" (a field with observer behind the scene, duh). The (ab)use of underscores is to avoid name clashes with upstream field names. Specifically "_" (roSgNode subtype) could have been named "_type" and "__" (child nodes) be "_children" - but i am a lazy typist and go as short as i can.
Note there are no
turducken issues in specifying the field values in B/S and no confusion! I.e. if one needs an array of strings, one would not end up with
<MyComp messages="["hi", "hello", "world", "none"]">
<!-- after failing with -->
<MyComp messages="['hi', 'hello', 'world', 'none']"
Note also that nodes with IDs currently get "auto-published" both as scene fields and in `m` - no need of findNode()ry. I am a bit ambivalent about choosing only one of the two - the reason is that the fields convenient to manipulate from main but glacial slow - where `m` variables are fast but encapsulated to the scenic scripts only.Here is for comparison what the original example looks like (only the XML here):
<?xml version="1.0" encoding="utf-8" ?>
<!--********** Copyright 2016 Roku Corp. All Rights Reserved. **********-->
<component name = "EventObserverExample" extends = "Scene" >
<script type = "text/brightscript" >
<![CDATA[
sub init()
m.top.backgroundURI = "pkg:/images/rsgde_bg_hd.jpg"
example = m.top.findNode("textRectangle")
examplerect = example.boundingRect()
centerx = (1280 - examplerect.width) / 2
centery = (720 - examplerect.height) / 2
example.translation = [ centerx, centery ]
m.movinglabel = m.top.findNode("movingLabel")
m.defaulttext = "All The Best Videos!"
m.alternatetext = "All The Time!!!"
m.textchange = false
scrollback = m.top.findNode("scrollbackAnimation")
scrollback.control = "start"
texttimer = m.top.findNode("textTimer")
texttimer.observeField("fire", "changetext")
texttimer.control = "start"
m.top.setFocus(true)
end sub
sub changetext()
if (m.textchange = false) then
m.movinglabel.text = m.alternatetext
m.textchange = true
else
m.movinglabel.text = m.defaulttext
m.textchange = false
end if
end sub
]]>
</script>
<children>
<Rectangle
id = "textRectangle"
width = "640"
height = "60"
color = "0x10101000" >
<Label
id = "movingLabel"
width = "280"
height = "60"
text = "All The Best Videos!"
horizAlign = "center"
vertAlign = "center" />
</Rectangle>
<Animation
id = "scrollbackAnimation"
duration = "10"
repeat = "true"
easeFunction = "linear" >
<Vector2DFieldInterpolator
key = "[ 0.0, 0.5, 1.0 ]"
keyValue = "[ [0.0, 0.0], [360.0, 0.0], [0.0, 0.0] ]"
fieldToInterp = "movingLabel.translation" />
</Animation>
<Timer
id = "textTimer"
repeat = "true"
duration = "5" />
</children>
</component>
I'd like to hear some opinions from people that have tried RSG - beginners or advanced. Do i make any sense in what i am trying to do? Does it seem more simple or more complicated than the Co's beloved "xmlography"? Also the m v. fields question.
My biggest issue remains the
lack of first-class function fields in RSG, thus having to pass code as strings to the scene. Also, i haven't touched the roSgScreen main loop - no opinion as of yet if it's helpful to tuck it away (i have the feeling i'll get opinionated when i get to use roMessageEvent observers).