GUI Tutorial

This tutorial was originally posted by crovea on our archive development forum, but we've copied here to save you the trouble of visiting the seven levels of spam hell.

Thrive GUI tutorial - CEGUI from image to anything!


Hello everyone

I wanted to create this tutorial to help share my knowledge about how to implement the parts of the GUI for thrive, and hopefully show how easy it is, even with no programming or "xml" experience!

As you may know, we use Ogre3D as our graphics library/engine and in that context there are a number of available GUI libraries that are made specifically for Ogre3D and this is where CEGUI comes in, a very flexible gui library with great modding abilities without the need to change much of any code. CEGUI uses a number of "XML" style files that define most of what makes up the GUI and this tutorial is focused on explaining how they work and how you can help add to and improve the GUI!

This tutorial does not deal with how to make the actual art of the elements of the gui. It is assumed that the art is already ready for each gui element and simply needs to be put into the game.

There are 6 stages to the gui, which can be seen in the 6 sections below. They can generally be followed in chronological order when implementing the gui!

Raw Images

These are large basic images, in which multiple gui elements are gathered side by side with no particular structure. These images are used in the imageset files that define the pixel positions and sizes for each element.
Certain kinds of items may benefit from being split into parts to allow better scaling and avoid any kind of blurry or pixelated effects. A square button may be split into 4 corners, 4 sides and center filler content, such that the corners are never scaled and a vertical side is only scaled vertically etc. The splitting of elements do not need to be done in these images as it can be done by defining the splitting pixel positions in the imagesets, but it can improve clarity.

Note that you want to use alpha for transparency in these raw image files.

Example of image:

xvhlznI.png

XML Files

XML files aren't actually part of CEGUI in their typical form, rather they are a general way to write information in text files in a way that is both readable by humans and "parsable" by a computer. XML files are used extensively in almost every large game and for many things outside games. Many project files saved by various programs likely uses xml files, but with a different file ending.

XML files are made up of tags that define structure, free text that represent some piece of data, often just a name or a number, and properties
that also contain pieces of data for the contents of specific tags. When writing XML you can generally replace any use of free text with a property and vice versa, but different styles will tell you to use properties for certain things and text for others.

An XML tag has a start tag and an end tag, which looks like this:

<student> </student>

If we want the student tag to contain some basic information we can simply write some free text inside it:

<student>Jacob Jensen</student>

And that's a basic piece of valid XML! You can also have tags inside other tags, to create some structure in your data. You also often have multiple instances of the same tag to represent multiple instances of that element:

<class>
<student>Jacob Jensen</student>
<student>Hannibal Lector</student>
</class>

We now have some data representing a class with multiple students in it and their names! Let us add the age of the students using properties and at the same time use indention to make the XML easier to read:

<class>
    <student age="24">
         Jacob Jensen
    </student>
    <student age="45">
         Hannibal Lector
    </student>
</class>

All we need now to have a complete XML document is a special header tag that tells computers that this is xml and what version of xml it uses:

<?xml version="1.0"?>
<class>
    <student age="24">
         Jacob Jensen
    </student>
    <student age="45">
         Hannibal Lector
    </student>
</class>

One more thing to know is that if you have a tag without any free text inside it, perhaps only using properties, you can do with just a single tag that ends with "/>", such as this:

<student age="24" name="Jacob Jensen"/>

And now you know XML! The next four sections use specialised XML files that have a specified structure, meaning they must have certain tags and certain properties.

Imagsets

As mentioned in the previous section, the imagesets are a restricted form of XML files. They must start with a <Imageset> tag and contain a number of <Image> tags that each represent a gui element that is in the raw image file. The imageset tag must have a number of attributes:

  • imagefile - This specifies the raw image file that this imageset reads from. For the currently used gui in thrive the value is "ThriveGeneric.png"
  • name - This is a name for the imageset, in thrive we choose to make this match with the raw image name: "ThriveGeneric"
  • nativeHorzRes - The horizontal resolution of the raw image file. e.g. "1280"
  • nativeVertRes - The vertical resolution of the raw image file. e.g. "720"
  • version - The version of the imageset syntax we use, this is to allow newer version of CEGUI to change how imageset files are structured without breaking older imageset files. The current version is "2".
  • autoScaled - This property determines how to scale elements in the image. We simply use "vertical" as it's value here, as that is read by CEGUI to scale things vertically and simply maintain aspect ratio horizontally.

This leaves us with an Imageset tag that looks something like this:

<Imageset autoScaled="vertical" imagefile="ThriveGeneric.png" name="ThriveGeneric" nativeHorzRes="1280" nativeVertRes="720" version="2">
</Imageset>

We then want to add an image tag for each gui element that we want and have a picture for in the raw image file. The Image tags have the properties:

  • name - This is the name for the gui element. It is important that we choose something sensible here as it will be used when we start setting up our gui. e.g. "ThriveIcon".
  • xPos - This is the pixel x-coordinate for the upper-left-most corner of the image for this element, in the raw image. On windows, you can find this by opening the raw image in paint, and mousing over the upper-left-most corner and reading the X,Y values in the bottom left of the paint window. e.g. "100".
  • yPos - This is the pixel y-coordinate, found as above.
  • width - This is the pixel-width of the element. This can be found in windows by mousing over the upper-right-most corner of the element in the raw image, and subtracting the x-coordinate from this value.
  • height - The pixel-height value of the element, can be found similarly to above.

We don't use an end tag for Image tags, so we end up with something like this:

<Imageset autoScaled="vertical" imagefile="ThriveGeneric.png" name="ThriveGeneric" nativeHorzRes="1280" nativeVertRes="720" version="2">
    <Image name="ThriveIcon" xPos="100" yPos="50" width="120" height="120" />
    <Image name="ThriveIconAlternative" xPos="240" yPos="180" width="120" height="120" />
</Imageset>

What is above is now a valid imageset. note that we don't use the normal XML header, as we don't actually call this an xml file, but rather an imageset file, and the file is also saved with the file-ending ".imageset".

One more thing to note, however, is when we want to make, say a button, that scales without pixelation issues, we want to define multiple parts of the button. We want to define four corners, four edges and a filler Image, which will look something like:

<Image name="ButtonNormalLeft" xPos="0" yPos="91" width="4" height="6" />
<Image name="ButtonNormalRight" xPos="17" yPos="91" width="4" height="6" />
<Image name="ButtonNormalTop" xPos="5" yPos="87" width="4" height="4" />
<Image name="ButtonNormalBottom" xPos="5" yPos="97" width="4" height="4" />
<Image name="ButtonNormalTopLeft" xPos="0" yPos="87" width="4" height="4" />
<Image name="ButtonNormalTopRight" xPos="17" yPos="87" width="4" height="4" />
<Image name="ButtonNormalBottomLeft" xPos="0" yPos="97" width="4" height="4" />
<Image name="ButtonNormalBottomRight" xPos="17" yPos="97" width="4" height="4" />
<Image name="ButtonNormalBackground" xPos="5" yPos="92" width="2" height="2" />

Which defines the parts for this button:

fEDACjF.png

Allowing it to be cleanly scaled by CEGUI into something like:

Roe3Jbv.png

We will define later how this is used.

For a full example, you can find the full ThriveGeneric.imageset here: http://87.230.23.195/svn/thrive_assets/gui/imagesets/ThriveGeneric.imageset

Looknfeel

If you're looking to create new types of gui elements, such as a table widget, or perhaps a scrolling icon-bar then you will want to head into the looknfeel files, otherwise you can skip this section without issue. For the people interested, I'll give a short explanation here.

Looknfeel files are again xml-styled files that define how specific types of gui elements are structured, also called skinning files.
The file starts with a <Falagard> tag, which is the name of the CEGUI contributor that invented the skinning files, this tag has a single version tag.

Inside the Falagard tag, you then have a number of <WidgetLook> tags, each with a name property foe name of your cegui element type.
Inside the WidgetLook tag you then have a number of <PropertyDefinition> tags, which are like variables that are used for the rest of the WidgetLook, they have the following properties: redrawOnWrite, initialValue, type, name all of which should be fairly self-explanatory. The type can be things like "Colour" or "VerticalTextFormatting", see some examples for more information.

The WidgetLook tags can then have a number of tags that define the structure of the Element/widget, such as <ImagerySection>, <StateImagery>, <NamedArea>, <Child> and more. See official CEGUI documentation and examples for more details:
http://static.cegui.org.uk/docs/0.8.2/fal_tut1.html

You can find an example from the current gui in thrive here: http://87.230.23.195/svn/thrive_assets/gui/looknfeel/Thrive.looknfeel

Schemes

Schemes like looknfeel files can be largely skipped unless you're planning on creating new types of gui elements, it can however be useful to look into these files and see what types are available. They like the other CEGUI specific files, are XML formatted.

The Scheme files start with a <GUIScheme> with a version property, and a name property. The GUIScheme tag then contains <Imageset> tags referencing imagesets that are used in the Looknfeel files, <Font> tags for available fonts and font sizes, <LookNFeel> tags for referencing looknfeel files. These three tags all have a single filename property.
Finally we have the <FalagardMapping> tags which map existing gui element archetypes (such as "button" or "image") to looknfeel definitions allowing better scaling of square elements through the corner, edge and filler style image splitting and dynamic elements such as scrollbars. FalagardMapping tags have a windowType property which defines a name for the new type of element/widget, targetType property which reference an existing archetype of widget/button to which the Looknfeel is applied, the targetType defines which things are possible with the widget, such as "pressing" and "scrolling", renderer property which is the internal CEGUI system that should render this type and finally the lookNFeel property that defines which looknfeel definition that should be used.

This all get's a bit difficult to understand and you're probably better off looking at the official documentation: http://cegui.org.uk/wiki/Scheme_files

See an example currently being used here: http://87.230.23.195/svn/thrive_assets/gui/schemes/Thrive.scheme

Layouts

Layout files is the next important and almost final step in getting your gui looking right! They are XML styled files that hierarchically defines the types, dimensions and positions of the gui windows, as well as any optional properties (such as color).

The layout files start with a <GUILayout> tag with a single version property and then jumps right into <Window> tags. The Window tags simply have a name and a type property, the type property can be any type defined in the scheme files that are being loaded by the game, such as "Button" or "Image". The windows then have two tags inside them: <Property> tag and other Window tags that are then relative to the parent window. The reason the property tags here are tags instead of just more properties are because these properties contain two sub-properties and because tags are better suited for when you have a variable number of properties. The property tags have a name property for the property of the window you want to set and value property for the value you are setting it to. Here is an example:

<GUILayout version="4" >
    <Window name="MyButton" type="Thrive/Button">
        <Property name="Position" value="{{0.5,5},{0.5,0}}" />
        <Property name="Image" value="MyButtonImage" />
        <Property name="Size" value="{{0.08,0},{0.06,0}}" />
        <Property name="Text" value="DO STUFF" />
        <Property name="Font" value="Thrive-10" />
    </Window>
</GUILayout>

The Position and Size properties have some strange looking values and deserve some extra explanation, this is because they are split into X and Y as you would expect but also split into relative and absolute values. The relative values work like a percentage of the parent window and the absolute values are absolute pixel numbers that are added afterwards. The value: 0.5,5},{0.5,0 can be understood as {X,Y} where X= {0.5,5} and Y={0.5,0}, then the X value means a position 50% off the left side of the parent window and then 5 pixels more to the left afterwards. This way of specifying positions/sizes is called Unified Dimensions in CEGUI.
Note that the properties used here are specific to the window type, while every window may have position and size, the text, font and even image are not common to every window, and naturally other windows will have other properties that are defined by CEGUI beforehand or in the looknfeel files.
And that is pretty much all there is to the layout files

The full example for the current microbe stage gui can be found here: http://87.230.23.195/svn/thrive_assets/gui/layouts/MicrobeStage.layout

Lua

Now fancy buttons and flashy frames aren't too much good to us if we can't attach any functionality to it, and this is where we need to do a little programming! I won't teach you to do lua here so if you're not feeling too interested in learning it, you can always ask programmers such as myself to do this part, as it isn't much of a hassle and will often require additional code from the programmers to get it working right regardless.
The following code will attach an eventhandler for the push event on a button we have created called MyButton, that is a child window of a frame we called MyButtonFrame, which is automatically a child of the root window.

function initialise()
    local rootGuiWindow =  Engine:currentGameState():rootGUIWindow()
    local mybutton= rootGuiWindow:getChild("MyButtonFrame"):getChild("MyButton")
    mybutton:registerEventHandler("Clicked", buttonClicked)
end

function buttonClicked()
    showMessage("You Clicked A button!")
end

We simply grab the outermost window using the indirect CEGUI function rootGUIWindow() and then we dive into the window hierarchy that we defined in the layout files to finally get a reference to the button and we attach an event hander function. The event handler function is simply defined below as "buttonClicked()" and all it does here, is display a message to the user.

And that's it! Please leave any question, corrections or comments below!*

*Except don't, because you can't comment on Wiki posts.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License