Repository: sjbarag/brs
Pull request #518 (2020-08-25 23:13:15)

feat(rsg): Add Scene Node 
This PR includes the ability to create a Scene node/component.


Patch:
diff --git a/src/brsTypes/components/ComponentFactory.ts b/src/brsTypes/components/ComponentFactory.ts
index 6ad0cca..ea1171c 100644
--- a/src/brsTypes/components/ComponentFactory.ts
+++ b/src/brsTypes/components/ComponentFactory.ts
@@ -10,6 +10,7 @@ import {
     MarkupGrid,
     ContentNode,
     Timer,
+    Scene,
 } from "..";
 
 export enum BrsComponentName {
@@ -24,6 +25,7 @@ export enum BrsComponentName {
     MarkupGrid = "MarkupGrid",
     ContentNode = "ContentNode",
     Timer = "Timer",
+    Scene = "Scene",
 }
 
 // TODO: update with more components as they're implemented.
@@ -56,6 +58,8 @@ export class ComponentFactory {
                 return new ContentNode(name);
             case BrsComponentName.Timer:
                 return new Timer([], name);
+            case BrsComponentName.Scene:
+                return new Scene([], name);
             default:
                 return;
         }
diff --git a/src/brsTypes/components/Scene.ts b/src/brsTypes/components/Scene.ts
new file mode 100644
index 0000000..f36039b
--- /dev/null
+++ b/src/brsTypes/components/Scene.ts
@@ -0,0 +1,20 @@
+import { FieldModel } from "./RoSGNode";
+import { Group } from "./Group";
+import { AAMember } from "./RoAssociativeArray";
+
+export class Scene extends Group {
+    readonly defaultFields: FieldModel[] = [
+        { name: "backgroundURI", type: "uri" },
+        { name: "backgroundColor", type: "string", value: "0x000000FF" },
+        { name: "backExitsScene", type: "boolean", value: "true" },
+        { name: "dialog", type: "node" },
+        { name: "currentDesignResolution", type: "assocarray" },
+    ];
+
+    constructor(initializedFields: AAMember[] = [], readonly name: string = "Scene") {
+        super([], name);
+
+        this.registerDefaultFields(this.defaultFields);
+        this.registerInitializedFields(initializedFields);
+    }
+}
diff --git a/src/brsTypes/index.ts b/src/brsTypes/index.ts
index 12f19ef..4e300cd 100644
--- a/src/brsTypes/index.ts
+++ b/src/brsTypes/index.ts
@@ -21,6 +21,7 @@ import { BrsInterface } from "./BrsInterface";
 import { RoSGNode } from "./components/RoSGNode";
 import { Font } from "./components/Font";
 import { Group } from "./components/Group";
+import { Scene } from "./components/Scene";
 
 export * from "./BrsType";
 export * from "./Int32";
@@ -46,6 +47,7 @@ export * from "./components/RoInvalid";
 export * from "./components/RoSGNodeEvent";
 export * from "./components/RoSGNode";
 export * from "./components/Group";
+export * from "./components/Scene";
 export * from "./components/LayoutGroup";
 export * from "./components/Rectangle";
 export * from "./components/Label";
diff --git a/src/parser/ComponentScopeResolver.ts b/src/parser/ComponentScopeResolver.ts
index 078fac4..83c2a7e 100644
--- a/src/parser/ComponentScopeResolver.ts
+++ b/src/parser/ComponentScopeResolver.ts
@@ -79,7 +79,7 @@ export class ComponentScopeResolver {
                 // BRS hasn't implemented every node type in the reference implementation!  For now,
                 // let's warn when we detect unknown subtypes.
                 console.error(
-                    `Warning: XML component '${previousComponent.extends}' extends unknown component '${previousComponent.name}'. Ignoring extension.`
+                    `Warning: XML component '${previousComponent.name}' extends unknown component '${previousComponent.extends}'. Ignoring extension.`
                 );
                 return Promise.resolve();
             }


Test patch:
diff --git a/test/brsTypes/components/Scene.test.js b/test/brsTypes/components/Scene.test.js
new file mode 100644
index 0000000..9f02a3d
--- /dev/null
+++ b/test/brsTypes/components/Scene.test.js
@@ -0,0 +1,39 @@
+const brs = require("brs");
+const { Scene } = brs.types;
+
+describe("Scene", () => {
+    describe("stringification", () => {
+        it("inits a new Scene component", () => {
+            let scene = new Scene();
+
+            expect(scene.toString()).toEqual(
+                `<Component: roSGNode:Scene> =
+{
+    change: <Component: roAssociativeArray>
+    focusable: false
+    focusedchild: invalid
+    id: 
+    visible: true
+    opacity: 1
+    translation: <Component: roArray>
+    rotation: 0
+    scale: <Component: roArray>
+    scalerotatecenter: <Component: roArray>
+    childrenderorder: renderLast
+    inheritparenttransform: true
+    inheritparentopacity: true
+    clippingrect: <Component: roArray>
+    renderpass: 0
+    muteaudioguide: false
+    enablerendertracking: false
+    rendertracking: disabled
+    backgrounduri: 
+    backgroundcolor: 0x000000FF
+    backexitsscene: true
+    dialog: invalid
+    currentdesignresolution: <Component: roAssociativeArray>
+}`
+            );
+        });
+    });
+});
diff --git a/test/e2e/BrsComponents.test.js b/test/e2e/BrsComponents.test.js
index a4d88c3..4ef3d1f 100644
--- a/test/e2e/BrsComponents.test.js
+++ b/test/e2e/BrsComponents.test.js
@@ -761,4 +761,31 @@ describe("end to end brightscript functions", () => {
             "true",
         ]);
     });
+
+    test("components/Scene.brs", async () => {
+        await execute([resourceFile("components", "Scene.brs")], outputStreams);
+
+        expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([
+            "scene node type:",
+            "Node",
+            "scene node subtype:",
+            "Scene",
+            "scene node backs exit scene:",
+            "true",
+            "scene node background uri:",
+            "/images/arrow.png",
+            "scene node background color:",
+            "0xEB1010FF",
+            "extended scene node type:",
+            "Node",
+            "extended scene node subtype:",
+            "ExtendedScene",
+            "extended scene node backs exit scene:",
+            "true",
+            "extended scene node background uri:",
+            "/images/arrow.png",
+            "extended scene node background color:",
+            "0xEB1010FF",
+        ]);
+    });
 });
diff --git a/test/e2e/resources/components/ExtendedScene.xml b/test/e2e/resources/components/ExtendedScene.xml
new file mode 100644
index 0000000..8d60cb9
--- /dev/null
+++ b/test/e2e/resources/components/ExtendedScene.xml
@@ -0,0 +1,7 @@
+
+<?xml version="1.0" encoding="UTF-8"?>
+<component name="ExtendedScene" extends="Scene">
+    <interface>
+        <field id="extendSceneStringField" type="string" value="this extends scene" />
+    </interface>
+</component>
diff --git a/test/e2e/resources/components/Scene.brs b/test/e2e/resources/components/Scene.brs
new file mode 100644
index 0000000..c378540
--- /dev/null
+++ b/test/e2e/resources/components/Scene.brs
@@ -0,0 +1,24 @@
+sub main()
+    sceneNode = createObject("roSGNode", "Scene")
+    print "scene node type:" type(sceneNode) ' => Node
+    print "scene node subtype:" sceneNode.subtype() ' => Scene
+    print "scene node backs exit scene:" sceneNode.backExitsScene ' => true
+
+    sceneNode.backgroundUri = "/images/arrow.png"
+    print "scene node background uri:" sceneNode.backgroundUri
+
+    sceneNode.backgroundColor = "0xEB1010FF"
+    print "scene node background color:" sceneNode.backgroundColor
+
+    extendedSceneNode = createObject("roSGNode", "ExtendedScene")
+    print "extended scene node type:" type(extendedSceneNode) ' => Node
+    print "extended scene node subtype:" extendedSceneNode.subtype() ' => ExtendedScene
+    print "extended scene node backs exit scene:" extendedSceneNode.backExitsScene ' => true
+
+    extendedSceneNode.backgroundUri = "/images/arrow.png"
+    print "extended scene node background uri:" extendedSceneNode.backgroundUri
+
+    extendedSceneNode.backgroundColor = "0xEB1010FF"
+    print "extended scene node background color:" extendedSceneNode.backgroundColor
+
+end sub