An Introduction to Trees in Quorum

In this tutorial, we will learn how to use Trees in the Quorum Game Engine. Trees are an interface tool that represents related items in a hierarchy. For example, a Quorum Project’s file directory is a Tree, which may look something like ProjectName, under ProjectName the Source Code, and under Source Code a few classes, say Class1.quorum, Class2.quorum, and main.quorum.

This image is an example of a Tree.

In Quorum, a Tree contains some number of TreeItem objects. In the above example, ProjectName, Source Code, Class1.quorum, Class2.quorum, and main.quorum are all TreeItems.

For this tutorial, we will set the focus on the Tree as soon as the program starts, allowing the arrow keys to be used to navigate through the TreeItems. The Up Arrow Key and Down Arrow Key move the selection up or down one, respectively, and the Left Arrow Key and Right Arrow Key close or open a subtree, respectively. The enter key will start the Behavior of the currently selected TreeItem.

The Tree we create will be able to change the Color of a Drawable, depending on which TreeItem is selected, and it will say the new Color. To start, create a new Game Application project.

Tree of Color

In order to use a Tree, we must include the Tree and TreeItem libraries. We will also need the Drawable, Color, and Texture libraries, giving us the following use statements:
use Libraries.Interface.Controls.Tree
use Libraries.Interface.Controls.TreeItem
use Libraries.Game.Graphics.Drawable
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Texture

Since we want the Tree to be usable as soon as the game begins, everything we add to the main class will be in the CreateGame action. To begin, we must create a Texture to go along with each TreeItem. A Texture is similar to a Drawable, with the primary distinction being that a Drawable is an object that comes with coordinates, having a position in space, while a Texture only has the visual component. For our example, we will use a small circle next to each TreeItem with the color we want to change the rectangle to, using the following lines of code:

Color color

Texture textureA
Texture textureA_1

Texture textureB
Texture textureB_1
Texture textureB_2
Texture textureB_3
Texture textureB_3_1
Texture textureB_3_2

Texture textureC
Texture textureC_1
Texture textureC_2

textureA:LoadFilledCircle(10, color:Red())
textureA_1:LoadFilledCircle(10, color:CustomColor(1, 0.75, 0.75, 1))

textureB:LoadFilledCircle(10, color:Blue())
textureB_1:LoadFilledCircle(10, color:CustomColor(0, 0, 0.5, 1))
textureB_2:LoadFilledCircle(10, color:CustomColor(0, 1, 1, 1))
textureB_3:LoadFilledCircle(10, color:CustomColor(0.5, 0, 0.5, 1))
textureB_3_1:LoadFilledCircle(10, color:CustomColor(0.25, 0, 0.25, 1))
textureB_3_2:LoadFilledCircle(10, color:CustomColor(0.75, 0, 0.75, 1))

textureC:LoadFilledCircle(10, color:Green())
textureC_1:LoadFilledCircle(10, color:CustomColor(0.5, 0.5, 0, 1))
textureC_2:LoadFilledCircle(10, color:CustomColor(0, 0.5, 0, 1))

For the purposes of this tutorial, we suggest to simply use the values above for the CustomColor action. However, if you would like to learn more, see the documentation on the Color class.

Next, we will create our rectangle, which will be a Drawable, by adding the following lines of code:

Drawable box
box:LoadFilledRectangle(250, 250, color:White())
box:SetPosition(400, 200)
Add(box)

Additionally, we will create an outline for the space where our Tree will be. This is only for a appearances, but is as simple as creating another Drawable, shown below:

Drawable outline
outline:LoadRectangle(250, 250, color:Black())
outline:SetPosition(150, 200)
Add(outline)

Now we will create our Tree, as well as our TreeItem objects, using the following lines:

Tree tree

TreeItem itemA
TreeItem itemA_1

TreeItem itemB
TreeItem itemB_1
TreeItem itemB_2
TreeItem itemB_3
TreeItem itemB_3_1
TreeItem itemB_3_2

TreeItem itemC
TreeItem itemC_1
TreeItem itemC_2

With our TreeItem objects created, we now need to Initialize them. There are a few different Initialize actions, but for our example, we will use the format which accepts a text and Texture parameter. The text parameter is the name of the TreeItem, and we will name each TreeItem according to the Color we want it to change the rectangle to. This gives us the following lines:

itemA:Initialize("Red", textureA)
itemA_1:Initialize("Pink", textureA_1)

itemB:Initialize("Blue", textureB)
itemB_1:Initialize("Navy", textureB_1)
itemB_2:Initialize("Cyan", textureB_2)
itemB_3:Initialize("Purple", textureB_3)
itemB_3_1:Initialize("Dark Purple", textureB_3_1)
itemB_3_2:Initialize("Light Purple", textureB_3_2)

itemC:Initialize("Green", textureC)
itemC_1:Initialize("Olive", textureC_1)
itemC_2:Initialize("Forest", textureC_2)

Now it is time to add our TreeItem objects to the Tree. First, we want to make our subtrees by adding itemA_1 to itemA, adding itemB_1, itemB_2, and itemB_3 to itemB, adding itemB_3_1 and itemB_3_2 to itemB_3, and adding itemC_1 and itemC_2 to itemC. Then we will add itemA, itemB, and itemC to our Tree. These tasks are accomplished with the following lines of code:

itemA:Add(itemA_1)

itemB:Add(itemB_1)
itemB:Add(itemB_2)
itemB:Add(itemB_3)
itemB_3:Add(itemB_3_1)
itemB_3:Add(itemB_3_2)

itemC:Add(itemC_1)
itemC:Add(itemC_2)

tree:Add(itemA)
tree:Add(itemB)
tree:Add(itemC)

Next, we will add the Tree to the game window. First we set its position, followed by a Resize action call, and finally Add. The Resize action has the Tree organize its TreeItem objects in space so that they can be seen; without this, the TreeItem objects would overlap on top of one another. Lastly, we will set the focus on the Tree, allowing us to navigate it. This gives the following code in the main class, so far:

use Libraries.Game.Game
use Libraries.Interface.Controls.Tree
use Libraries.Interface.Controls.TreeItem
use Libraries.Game.Graphics.Drawable
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Texture

class Main is Game

    action Main
        StartGame()
    end

    action CreateGame
        Color color

        Texture textureA
        Texture textureA_1

        Texture textureB
        Texture textureB_1
        Texture textureB_2
        Texture textureB_3
        Texture textureB_3_1
        Texture textureB_3_2

        Texture textureC
        Texture textureC_1
        Texture textureC_2

        textureA:LoadFilledCircle(10, color:Red())
        textureA_1:LoadFilledCircle(10, color:CustomColor(1, 0.75, 0.75, 1))

        textureB:LoadFilledCircle(10, color:Blue())
        textureB_1:LoadFilledCircle(10, color:CustomColor(0, 0, 0.5, 1))
        textureB_2:LoadFilledCircle(10, color:CustomColor(0, 1, 1, 1))
        textureB_3:LoadFilledCircle(10, color:CustomColor(0.5, 0, 0.5, 1))
        textureB_3_1:LoadFilledCircle(10, color:CustomColor(0.25, 0, 0.25, 1))
        textureB_3_2:LoadFilledCircle(10, color:CustomColor(0.75, 0, 0.75, 1))

        textureC:LoadFilledCircle(10, color:Green())
        textureC_1:LoadFilledCircle(10, color:CustomColor(0.5, 0.5, 0, 1))
        textureC_2:LoadFilledCircle(10, color:CustomColor(0, 0.5, 0, 1))

        Drawable box
        box:LoadFilledRectangle(250, 250, color:White())
        box:SetPosition(400, 200)
        Add(box)

        Drawable outline
        outline:LoadRectangle(250, 250, color:Black())
        outline:SetPosition(150, 200)
        Add(outline)

        Tree tree

        TreeItem itemA
        TreeItem itemA_1

        TreeItem itemB
        TreeItem itemB_1
        TreeItem itemB_2
        TreeItem itemB_3
        TreeItem itemB_3_1
        TreeItem itemB_3_2

        TreeItem itemC
        TreeItem itemC_1
        TreeItem itemC_2

        itemA:Initialize("Red", textureA)
        itemA_1:Initialize("Pink", textureA_1)

        itemB:Initialize("Blue", textureB)
        itemB_1:Initialize("Navy", textureB_1)
        itemB_2:Initialize("Cyan", textureB_2)
        itemB_3:Initialize("Purple", textureB_3)
        itemB_3_1:Initialize("Dark Purple", textureB_3_1)
        itemB_3_2:Initialize("Light Purple", textureB_3_2)

        itemC:Initialize("Green", textureC)
        itemC_1:Initialize("Olive", textureC_1)
        itemC_2:Initialize("Forest", textureC_2)

        itemA:Add(itemA_1)

        itemB:Add(itemB_1)
        itemB:Add(itemB_2)
        itemB:Add(itemB_3)
        itemB_3:Add(itemB_3_1)
        itemB_3:Add(itemB_3_2)

        itemC:Add(itemC_1)
        itemC:Add(itemC_2)

        tree:Add(itemA)
        tree:Add(itemB)
        tree:Add(itemC)

        tree:SetPosition(150, 450)
        tree:Resize()
        Add(tree)
        tree:Focus()
    end

    action Update(number seconds)
    end
end

Now, when the project is run, the Tree appears, but it does nothing aside from let us view it.

This is an image of the unfinished Tree.

Before we continue, we need to design the Behavior we want the activation of our TreeItem objects to take. To do so, first create a new Quorum class, which we will name "ColorBehavior.quorum." This class will require the Behavior, BehaviorEvent, Color, Drawable, and Speech libraries, giving us the following use statements:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Drawable
use Libraries.Sound.Speech

The ColorBehavior class itself will inherit the Behavior class, and will need a Drawable, Color, and Text class variable. We will override the Run action, and will create actions to set the class variables, giving us the following template:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Drawable
use Libraries.Sound.Speech

class ColorBehavior is Behavior

    Drawable box = undefined
    Color color = undefined
    Text colorName = undefined

    action SetDrawable(Drawable item)
        box = item
    end

    action SetColor(Color newColor, Text newColorName)
        color = newColor
        colorName = newColorName
    end

    action Run(BehaviorEvent event)
    end
end

For the Run action, we need to change the Drawable’s color and say the color’s name. This is done through the following code:

action Run(BehaviorEvent event)
    if box not= undefined and color not= undefined and colorName not= undefined
        box:SetColor(color)
        Speech speech
        speech:Say(colorName, false)
    end
end

Note the conditional if statement; this is done as a safety measure to avoid crashing the program if no Drawable or Color is set from the main class. Altogether, the ColorBehavior class is as follows:

use Libraries.Interface.Behaviors.Behavior
use Libraries.Interface.Events.BehaviorEvent
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Drawable
use Libraries.Sound.Speech

class ColorBehavior is Behavior

    Drawable box = undefined
    Color color = undefined
    Text colorName = undefined

    action SetDrawable(Drawable item)
        box = item
    end

    action SetColor(Color newColor, Text newColorName)
        color = newColor
        colorName = newColorName
    end

    action Run(BehaviorEvent event)
        if box not= undefined and color not= undefined and colorName not= undefined
            box:SetColor(color)
            Speech speech
            speech:Say(colorName, false)
        end
    end
end

Returning to the main class, we now know that we need to create a Color for each TreeItem. Then we will set each to the proper color using the same values from before. This can be done through the following lines:

Color colorA
Color colorA_1

Color colorB
Color colorB_1
Color colorB_2
Color colorB_3
Color colorB_3_1
Color colorB_3_2

Color colorC
Color colorC_1
Color colorC_2

colorA = color:Red()
colorA_1 = color:CustomColor(1, 0.75, 0.75, 1)

colorB = color:Blue()
colorB_1 = color:CustomColor(0, 0, 0.5, 1)
colorB_2 = color:CustomColor(0, 1, 1, 1)
colorB_3 = color:CustomColor(0.5, 0, 0.5, 1)
colorB_3_1 = color:CustomColor(0.25, 0, 0.25, 1)
colorB_3_2 = color:CustomColor(0.75, 0, 0.75, 1)

colorC = color:Green()
colorC_1 = color:CustomColor(0.5, 0.5, 0, 1)
colorC_2 = color:CustomColor(0, 0.5, 0, 1)

Next, we will create a ColorBehavior object for each TreeItem, using the following lines:

ColorBehavior behaviorA
ColorBehavior behaviorA_1

ColorBehavior behaviorB
ColorBehavior behaviorB_1
ColorBehavior behaviorB_2
ColorBehavior behaviorB_3
ColorBehavior behaviorB_3_1
ColorBehavior behaviorB_3_2

ColorBehavior behaviorC
ColorBehavior behaviorC_1
ColorBehavior behaviorC_2

Now, we must set the Drawable and Color for each of those ColorBehavior objects. Since we want all of them to change the color of the same Drawable, we will use the "box" variable for all SetDrawable action calls. However, since we want each color change to be different, we will use the Color variables we created earlier for the SetColor action calls. In addition, recall that we need to provide the color’s name in text for the program to say it aloud. This is done by adding the following lines:

behaviorA:SetDrawable(box)
behaviorA_1:SetDrawable(box)

behaviorB:SetDrawable(box)
behaviorB_1:SetDrawable(box)
behaviorB_2:SetDrawable(box)
behaviorB_3:SetDrawable(box)
behaviorB_3_1:SetDrawable(box)
behaviorB_3_2:SetDrawable(box)

behaviorC:SetDrawable(box)
behaviorC_1:SetDrawable(box)
behaviorC_2:SetDrawable(box)

behaviorA:SetColor(colorA, "Red")
behaviorA_1:SetColor(colorA_1, "Pink")

behaviorB:SetColor(colorB, "Blue")
behaviorB_1:SetColor(colorB_1, "Navy")
behaviorB_2:SetColor(colorB_2, "Cyan")
behaviorB_3:SetColor(colorB_3, "Purple")
behaviorB_3_1:SetColor(colorB_3_1, "Dark Purple")
behaviorB_3_2:SetColor(colorB_3_2, "Light Purple")

behaviorC:SetColor(colorC, "Green")
behaviorC_1:SetColor(colorC_1, "Olive")
behaviorC_2:SetColor(colorC_2, "Forest")

Finally, we simply have to assign each ColorBehavior object to its respective TreeItem. This is done with the SetBehavior action call, using the following lines of code:

itemA:SetBehavior(behaviorA)
itemA_1:SetBehavior(behaviorA_1)

itemB:SetBehavior(behaviorB)
itemB_1:SetBehavior(behaviorB_1)
itemB_2:SetBehavior(behaviorB_2)
itemB_3:SetBehavior(behaviorB_3)
itemB_3_1:SetBehavior(behaviorB_3_1)
itemB_3_2:SetBehavior(behaviorB_3_2)

itemC:SetBehavior(behaviorC)
itemC_1:SetBehavior(behaviorC_1)
itemC_2:SetBehavior(behaviorC_2)

The full main class is as follows:

use Libraries.Game.Game
use Libraries.Interface.Controls.Tree
use Libraries.Interface.Controls.TreeItem
use Libraries.Game.Graphics.Drawable
use Libraries.Game.Graphics.Color
use Libraries.Game.Graphics.Texture

class Main is Game

    action Main
        StartGame()
    end

    action CreateGame
        Color color

        Texture textureA
        Texture textureA_1

        Texture textureB
        Texture textureB_1
        Texture textureB_2
        Texture textureB_3
        Texture textureB_3_1
        Texture textureB_3_2

        Texture textureC
        Texture textureC_1
        Texture textureC_2

        textureA:LoadFilledCircle(10, color:Red())
        textureA_1:LoadFilledCircle(10, color:CustomColor(1, 0.75, 0.75, 1))

        textureB:LoadFilledCircle(10, color:Blue())
        textureB_1:LoadFilledCircle(10, color:CustomColor(0, 0, 0.5, 1))
        textureB_2:LoadFilledCircle(10, color:CustomColor(0, 1, 1, 1))
        textureB_3:LoadFilledCircle(10, color:CustomColor(0.5, 0, 0.5, 1))
        textureB_3_1:LoadFilledCircle(10, color:CustomColor(0.25, 0, 0.25, 1))
        textureB_3_2:LoadFilledCircle(10, color:CustomColor(0.75, 0, 0.75, 1))

        textureC:LoadFilledCircle(10, color:Green())
        textureC_1:LoadFilledCircle(10, color:CustomColor(0.5, 0.5, 0, 1))
        textureC_2:LoadFilledCircle(10, color:CustomColor(0, 0.5, 0, 1))

        Drawable box
        box:LoadFilledRectangle(250, 250, color:White())
        box:SetPosition(400, 200)
        Add(box)

        Drawable outline
        outline:LoadRectangle(250, 250, color:Black())
        outline:SetPosition(150, 200)
        Add(outline)

        Tree tree

        TreeItem itemA
        TreeItem itemA_1

        TreeItem itemB
        TreeItem itemB_1
        TreeItem itemB_2
        TreeItem itemB_3
        TreeItem itemB_3_1
        TreeItem itemB_3_2

        TreeItem itemC
        TreeItem itemC_1
        TreeItem itemC_2

        itemA:Initialize("Red", textureA)
        itemA_1:Initialize("Pink", textureA_1)

        itemB:Initialize("Blue", textureB)
        itemB_1:Initialize("Navy", textureB_1)
        itemB_2:Initialize("Cyan", textureB_2)
        itemB_3:Initialize("Purple", textureB_3)
        itemB_3_1:Initialize("Dark Purple", textureB_3_1)
        itemB_3_2:Initialize("Light Purple", textureB_3_2)

        itemC:Initialize("Green", textureC)
        itemC_1:Initialize("Olive", textureC_1)
        itemC_2:Initialize("Forest", textureC_2)

        itemA:Add(itemA_1)

        itemB:Add(itemB_1)
        itemB:Add(itemB_2)
        itemB:Add(itemB_3)
        itemB_3:Add(itemB_3_1)
        itemB_3:Add(itemB_3_2)

        itemC:Add(itemC_1)
        itemC:Add(itemC_2)

        tree:Add(itemA)
        tree:Add(itemB)
        tree:Add(itemC)

        tree:SetPosition(150, 450)
        tree:Resize()
        Add(tree)
        tree:Focus()

        Color colorA
        Color colorA_1

        Color colorB
        Color colorB_1
        Color colorB_2
        Color colorB_3
        Color colorB_3_1
        Color colorB_3_2

        Color colorC
        Color colorC_1
        Color colorC_2

        colorA = color:Red()
        colorA_1 = color:CustomColor(1, 0.75, 0.75, 1)

        colorB = color:Blue()
        colorB_1 = color:CustomColor(0, 0, 0.5, 1)
        colorB_2 = color:CustomColor(0, 1, 1, 1)
        colorB_3 = color:CustomColor(0.5, 0, 0.5, 1)
        colorB_3_1 = color:CustomColor(0.25, 0, 0.25, 1)
        colorB_3_2 = color:CustomColor(0.75, 0, 0.75, 1)

        colorC = color:Green()
        colorC_1 = color:CustomColor(0.5, 0.5, 0, 1)
        colorC_2 = color:CustomColor(0, 0.5, 0, 1)

        ColorBehavior behaviorA
        ColorBehavior behaviorA_1

        ColorBehavior behaviorB
        ColorBehavior behaviorB_1
        ColorBehavior behaviorB_2
        ColorBehavior behaviorB_3
        ColorBehavior behaviorB_3_1
        ColorBehavior behaviorB_3_2

        ColorBehavior behaviorC
        ColorBehavior behaviorC_1
        ColorBehavior behaviorC_2

        behaviorA:SetDrawable(box)
        behaviorA_1:SetDrawable(box)

        behaviorB:SetDrawable(box)
        behaviorB_1:SetDrawable(box)
        behaviorB_2:SetDrawable(box)
        behaviorB_3:SetDrawable(box)
        behaviorB_3_1:SetDrawable(box)
        behaviorB_3_2:SetDrawable(box)

        behaviorC:SetDrawable(box)
        behaviorC_1:SetDrawable(box)
        behaviorC_2:SetDrawable(box)

        behaviorA:SetColor(colorA, "Red")
        behaviorA_1:SetColor(colorA_1, "Pink")

        behaviorB:SetColor(colorB, "Blue")
        behaviorB_1:SetColor(colorB_1, "Navy")
        behaviorB_2:SetColor(colorB_2, "Cyan")
        behaviorB_3:SetColor(colorB_3, "Purple")
        behaviorB_3_1:SetColor(colorB_3_1, "Dark Purple")
        behaviorB_3_2:SetColor(colorB_3_2, "Light Purple")

        behaviorC:SetColor(colorC, "Green")
        behaviorC_1:SetColor(colorC_1, "Olive")
        behaviorC_2:SetColor(colorC_2, "Forest")

        itemA:SetBehavior(behaviorA)
        itemA_1:SetBehavior(behaviorA_1)

        itemB:SetBehavior(behaviorB)
        itemB_1:SetBehavior(behaviorB_1)
        itemB_2:SetBehavior(behaviorB_2)
        itemB_3:SetBehavior(behaviorB_3)
        itemB_3_1:SetBehavior(behaviorB_3_1)
        itemB_3_2:SetBehavior(behaviorB_3_2)

        itemC:SetBehavior(behaviorC)
        itemC_1:SetBehavior(behaviorC_1)
        itemC_2:SetBehavior(behaviorC_2)

    end

    action Update(number seconds)
    end
end

When the project is run, activating a TreeItem now changes the color of the rectangle to match the TreeItem object’s name, and the program will say the color’s name. Note that each TreeItem can be activated either by double-clicking with the mouse, or by pressing Enter on a highlighted TreeItem.

This image shows the expected complete Tree.

The TreeSelection Class

In Quorum, Trees have a special tool that is used to manage which TreeItem is selected. This tool is the TreeSelection class. This class keeps track of the current selection by storing the specific and unique path to the current TreeItem, storing them in an Array of TreeItems from high level to low level. For example, the path to the "Olive" TreeItem in the above image is an Array of two TreeItems, starting with "Green," then "Olive." To demonstrate how selections work with Trees, we will add to the ColorBehavior class and have it output the selected TreeItem’s path when activated.

First, we will need to include a few more use statements in the ColorBehavior class. These are:

use Libraries.Interface.Selections.TreeSelection
use Libraries.Interface.Controls.Tree
use Libraries.Interface.Controls.TreeItem
use Libraries.Containers.Array

Now, we can add to the Run action. After the conditional if statement we already have, we need to get the current TreeSelection, which can be obtained from the current Tree. Since we are triggering the Behavior from a TreeItem variable in the main class, we can obtain the Tree from the TreeItem associated with the BehaviorEvent parameter. This is done by calling the BehaviorEvent’s GetItem action, but this returns an Item, not a TreeItem, so we will have to cast it. Then, we can get the Tree from our TreeItem, and then get the selection from the Tree. This is done with the following lines:

TreeItem treeItem = cast(TreeItem, event:GetItem())
Tree tree = treeItem:GetTree()
TreeSelection selection = tree:GetSelection()

Now that we have our TreeSelection, we can call the TreeSelection’s GetPath action to obtain the Array of TreeItems. For more information, see the tutorial on Arrays. Once we have the Array, we can obtain how many TreeItems there are with the Array’s GetSize action. This gives the following two lines:
Array treeItems = selection:GetPath()
integer size = treeItems:GetSize()

Since we do not know ahead of time how large the path is, we need to make use of repeating, specifically repeat while. In this repeat, we will traverse the Array in order and continually add each TreeItem’s name to a text variable. For more information, see the tutorial on Repeats. Finally, we will output the text variable once the repeat is completed. This gives the following lines of code:
integer counter = 0
text name = ""

repeat while counter < size
    TreeItem temp = treeItems:Get(counter)
    name = name + temp:GetName() + "\"
    counter = counter + 1
end

output name

Now, when we run the program, activating a TreeItem will also output the path to that TreeItem.

Next Tutorial

In the next tutorial, we will discuss TextBoxes, which describes how to use TextBoxes.