Finally, let's put all the examples we've seen previously in the tutorial together, to create a typical Scene Graph application. As with every application, this application has a purpose. And the purpose of this application is to present all the various node classes and design/development principles for Roku Scene Graph, to let you quickly select node classes and design ideas for your application.
Example Application: SceneGraphTutorial.zip
Tutorial Application Overview
SceneGraphTutorial.zip, you'll note that the package
components directory consists of the following directories and XML component files:
Contains the XML component files for the examples in Animation Markup
Contains the XML component files for the examples in Control Nodes Markup
Contains the XML component files for the examples in Events and Observers Markup
Contains the XML component files for the examples in Layout/Groups Markup
Contains the XML component files for the examples in Lists and Grids Markup
Contains the XML component files for the examples in Media Playback Markup
Contains the XML component files for the examples in Renderable Node Markup
Contains the XML component files for the examples in Sliding Panels Markup
Contains the XML component files for the examples in Typography Markup
Contains the XML component files for the examples in Widgets Markup
Contains the XML component files for the examples in Z-Order/Parent-Child Markup
XML Component Files
The scene component for the application, extended from the OverhangPanelSetScene node class
A generic Task node for reading Content Meta-Data for application content items from server XML files
A medium-size ListPanel node that lists the example categories
A medium-size Panel node that provides a description of each example category focused in the categories list panel
A full-size GridPanel node that provides a grid of example posters for user selection of each example
Note that if you've gone through the Scene Graph XML Tutorial from beginning to here, there is very little contained in
SceneGraphTutorial.zip that you haven't seen before. What this application does is pull together all the various Scene Graph nodes, components, designs, and development principles into a single application. So to complete the tutorial, we only need to describe certain aspects of the scene component file,
tutorialpanelsetscene.xml, and how it pulls together the entire application, along with the associated server XML files.
Tutorial Application Scene Component Description
tutorialpanelsetscene.xml, you'll see that there is no
<children> element XML markup to define Scene Graph nodes and components. Rather,
tutorialpanelsetscene.xml is used only to create, manipulate, and remove components in the application scene graph, which are defined in the all the other XML component files in the application
Initial Content Meta-Data Reading
In fact, a large part of
tutorialpanelsetscene.xml just creates and manipulates the same panel set described in OverhangPanelSetScene Markup. The big difference is not the panels or their sliding behavior, but in the greater amount of Content Meta-Data supplied by the server XML files supplied for the application, and allowing users to select a specific example item to view from the grids created by the
examplesgridpanel.xml file containing the content meta-data for each item.
To start the application, the
init() function runs a typical Task node content reader to get the initial content meta-data for the application:
m.readContentTask = createObject("roSGNode", "ContentReader")
m.readContentTask.contenturi = "http://www.sdktestinglab.com/Tutorial/content/categoriescontent.xml"
m.readContentTask.control = "RUN"
We're using the generic server XML file content reader Task node defined in
contentreader.xml. If you have any questions about how this works, you could review Task Markup in this tutorial. In this case, once the ContentNode node containing the content meta-data is complete, it triggers the
setcategories() callback function:
m.categoriespanel = m.top.panelSet.createChild("CategoriesListPanel")
m.categoriespanel.list.content = m.readContentTask.content
m.categoryinfopanel = m.top.panelSet.createChild("CategoryInfoPanel")
Dynamic Content Meta-Data Reading
setcategories() callback function creates the categories list panel and category description panel defined in the
categoryinfopanel.xml files, and adds them to the panel set. But importantly, when the ContentNode node created by the
m.readContentTask object is assigned to the
content field of the categories list panel object
m.categoriespanel.list, the entire application is now set up to dynamically download additional content meta-data as needed by user actions.
To do this, we set up two field observers in the
setcategories() function, one that observes the
itemFocused field of the categories panel LabelList node, and the other to observe the
focusedChild field of the category description panel. The first observer triggers a callback function that sends a category description to an
<interface> field of the category description panel object
m.categoryinfopanel, and creates an examples grid panel object to be populated with content meta-data dynamically by user focus on a category. The second controls the sliding of the panels in the panel set if the user selects a category, or presses the Right, Left, or Back remote control keys while focus is on a particular panel.
The key is that each item in the
categoriescontent.xml server file contains another
url content meta-data attribute that allows the rest of the application to dynamically load content meta-data from that URL:
title = "Renderable Nodes"
description = "Basic Nodes That Show Things
shortdescriptionline1 = "Renderable Node Markup"
url = "" />
shortdescriptionline1 content meta-data attributes can all be used in the application when the user focuses or selects the item in the
m.categoriespanel.list object, and the
url attribute can be used to populate the examples grid panel with content meta-data downloaded from that URL. This is done when the
showcategoryinfo() callback function is triggered by the user focusing on the category in the categories list panel list:
categorycontent = m.categoriespanel.list.content.getChild(m.categoriespanel.list.itemFocused)
m.categoryinfopanel.description = categorycontent.description
m.examplespanel = createObject("roSGNode", "examplesGridPanel")
m.examplespanel.overhangtext = categorycontent.shortdescriptionline1
m.examplespanel.gridcontenturi = categorycontent.url
The function first extracts the content meta-data for the category item by accessing the child ContentNode node for the item, using the
getChild() method with the
itemFocused field value of the categories list panel list as the parameter. After that, the item content meta-data
description attribute is assigned to the
<interface> element field of the categories description panel, causing that panel to display the description of the category. Then the examples grid panel object
m.examplespanel is created, and the object
gridcontenturi fields are assigned the values of the
url content meta-data attributes.
So the examples grid panel is being dynamically created and populated with content meta-data every time the user focuses on an item in the categories list panel list. Since the examples grid panel is configured to automatically download its content meta-data from its
<interface> element field, and configure the appearance of the panel based on the downloaded content meta-data, this download and configuration largely takes place before the user actually selects the category item. This automatic dynamic behavior makes the application feel quick and responsive to user actions; you can confirm this by actually using the application.
Running New Components Based On User Selection
The goal of a video-on-demand application is to allow a user to select a video for playback. Roku Scene Graph provides a wide variety of UI elements to allow a user to proceed from starting the application to actually playing the video in a variety of different ways, with many different custom UI designs possible. Note that all of the lists and grids, widgets, other built-in node classes, and custom markup components you create, can be used in virtually unlimited combinations and variations to design a unique user interface for your VOD application.
At the point at which the user is ready to select a video (or for that matter, an audio file) for playback, you'll want to have a field observer set up to trigger the callback function that will actually perform the media playback. Generally this will be an observer on an
itemSelected (or equivalent) field in a list or grid.
In our tutorial application, we set up this type of observer in the
slideexamplesgridpanel() callback function. This function is triggered by a focus on the categories description panel, is designed to detect whether the user has moved the focus to the examples grid panel, and take the appropriate actions:
if not m.top.panelSet.isGoingBack
The function first checks if the user is causing the panels in the panel set to slide to left or right. If the slide is towards the examples grid panel, the previously-created (and -configured) panel is added to the panel set using the
appendChild() method. Then we set the observer on the
itemSelected field of the examples grid panel grid, and move the focus to the panel. (If the user is causing the panels to slide the other way, towards the categories list panel, we set the focus on that panel.)
Now it's all up to the user (as always)...
Replacing Old Screens With New Screens
runselectedexample() callback function is largely the endpoint for this tutorial application. The application was designed to show the built-in node classes and design principles of Roku Scene Graph, and the
runselectedexample() function replaces the example grid panel and panel set with a "screen" showing a Roku Scene Graph example in action, if a user selects an example grid item in the examples grid panel.
Remember how we used the
url content meta-data attribute to configure the examples grid panel with dynamically-loaded content meta-data? This is the format of the content meta-data for each item in the examples grid panel from the server XML file:
shortdescriptionline1 = "Rectangle Node"
shortdescriptionline2 = "RectangleExample"
x = "0" y = "0" />
Most of the content meta-data attributes are used to configure the PosterGrid node in the examples grid panel. But one,
shortdescriptionline2, is used to supply the name of one of the dozens of component files defined in XML component files in the package
components sub-directories. And with that name, we can create and add the example item as a "screen" to the application. Note these lines in the
examplecontent = m.examplespanel.grid.content.getChild(m.examplespanel.grid.itemSelected)
example = examplecontent.shortdescriptionline2
First we access the specific item ContentNode node for the item using the
getChild() method and the examples panel grid
itemSelected field as the method parameter. Then we use string value of the attribute (the name of the component to run) to create the example component object, and append the component object to the panel set scene, while making the actual panel set itself invisible, and setting focus on the new component:
m.top.overhang.visible = false
m.top.panelset.visible = false
m.currentexample = createObject("roSGNode", example)
And the panel set "screen" is replaced with the
m.currentexample object screen, which appears just like the example with the corresponding name seen throughout this entire tutorial.
Replacing New Screens With Old Screens
In some cases, the new "example" screens are essentially complete applications themselves, with their own content meta-data, and have their own user selection "endpoint" (such as the video list example, which is the same example described in Video List Markup, which can play several user-selected videos).