Skip to content

GUI Guide

Peter Robinson edited this page Sep 14, 2023 · 15 revisions

Introduction

The GUI system in T2D allows you build dialogs with controls to handle things like menus and in-game option screens. The system has been handed down from T3D and remains very similar to its roots. However, there are a few differences to using the GUI system in T2D. Most notably, it's easy to build your own user interfaces out of sprites. Doing so has some advantages, but a basic knowledge of the GUI system is still necessary to setting up a SceneWindow. Because this topic is so expansive, we will start with an overview of how the GUI system works and them move on to the details of each control and how it can be used.

Please note: This guide is a work in progress. The GUI system is large and documenting it will take us some time. Please be patient. Also, the changes listed here apply to the latest version of the engine, currently in the development branch.

Overview

All GUI controls inherit from a single object aptly called GuiControl. GuiControl inherits from SimGroup which means that it can hold other controls inside of it. Each control has a set of its own properties, such as position and extent, and a set of shared properties which are contained in a different object called a GuiControlProfile. Every control needs to have a profile. The profile contains values such as the fill color. So the obvious question is, why do it this way? There are several advantages. First, you could change the entire look of a control simply by giving it a different profile. You could also change a value of a profile and immediately affect every control that uses it. So if all your buttons share a single button profile, you can change the button profile in one place and every button will change. This idea has been used with great success in other programming fields like web development where HTML and CSS fill the same roles as controls and profiles.

Unfortunately, there is also a downside to doing it this way. Namely, the GuiControlProfile has a lot of fields and each control can pick and choose which values it will actually use. How will you know which fields of the profile will be used with each control? By reading this documentation of course!

Putting Your GUIs on the Screen

Before we go an further, we need to cover some basics. Let's walk through the steps needed to get your GUIs up on the screen.

  1. Call createCanvas() to create an instance of GuiCanvas and wire it up to a window. The canvas will be a named object called "Canvas" and you can only have one. The canvas is actually a GuiControl as well and you can learn more about it in the List of Controls below. For now, let's just say the canvas is top level GUI element. If you want anything to appear before the user, you need to hand it to the canvas.

    createCanvas("Window Name");

  2. Call Canvas.setContent() to set a GuiControl as the current "screen" that appears before the user.

    Canvas.setContent(%myScreen);

In this example, %myScreen would hold a GuiControl and that control would probably have several children, including a SceneWindow. More on that later.

  1. When you want another GUI to go over the main screen, you push a "dialog" onto the Canvas.

    Canvas.pushDialog(%myDialog);

Here %myDialog also contains a GuiControl. This dialog could actually cover the whole screen, but then you might as well use setContent() instead. So it makes sense if you use this for the control to cover part of the screen. This has been compared to a save or open dialog that you see in most applications. Most importantly, when you push a dialog onto the canvas, the dialog will capture all input events until it is removed with popDialog(). You can stack multiple dialogs in the Canvas.

Common Properties

These are properties that exist on every control because they inherit them from GuiControl. It's super important to understand these so we'll cover them here before we get to the master list.

Position

This is the position of the top left corner of the control with (0,0) being the top left corner of its parent control's content area (i.e. the parent's area after applying margin, border, and padding). Larger y positions are further down the screen. This matches the way most screen/window positioning works in most operating systems, but it is backwards from the way a Scene works.

Extent and MinExtent

This is the width and height of the control. The extent will change automatically when its parent's extent changes based on the values of HorizSizing and VertSizing which are covered next. There's also a callback when the extent changes called onExtentChange(). It is important for SceneWindows to catch this to adjust their camera ratio. More on that in the SceneWindow section below. As you would expect, MinExtent is the smallest possible extent.

HorizSizing and VertSizing

Here's where things get confusing. These settings determine how a control is repositioned and resized when its parent is resized. This is based on its related size/position when it is added to its parent. The possible options are center, relative, left/top, right/bottom, and width/height.

  1. Center: The control will stay centered in its containing parent. The extent of the object will not change - only the position. You should note that the control will not start centered but will center if the parent is resized.
  2. Relative: The control will maintain the same position and extent to its parent. So if the parent doubles in size so will the control. Also the distance between the edges will double. Basically this matches zooming in and out on the GUI.
  3. Left/Top and Right/Bottom: Any change to the parent's size will be applied to the distance between the control and the specified edge which effectively anchors the control to the opposite edge.
  4. Width/Height: These settings allow the only extent of the control to change. So the control will remain the same number of pixels from the edges of its parent. This is kind of like anchoring the control to both edges.

Profile

This is the GuiControlProfile that the control will use. The profile holds a lot of information on how a control should look and can be quickly swapped to change the entire look of a control. See below for more.

Visible

Do you really need me to explain this? True means it gets rendered. False means it's hidden.

TooltipProfile, HoverTime, TooltipWidth, and Tooltip

Every control can have a tool tip. These four fields control how that tip works. The HoverTime determines how long the cursor should "hover" over a control before the tip appears (1000 = 1 second) and the width is used to determine how wide the tip is in pixels. The field Tooltip is the actual text of the tip. The TooltipProfile is another GuiControlProfile that is used to determine the look of the tip. If this is not set it will fall back to the profile for the control. It uses the profile's font, fontSize, fillColor, fontColor, and border settings.

Less Common Properties

There are some properties that are inherited from the GuiControl but aren't always used. These properties are more specific in their function.

Text and TextID

The text of a control can appear in different places depending on the control. For example, the button control will place the text on the button. The textID finds the text in the localization system and sets the text. You should only need one of these. Not all controls render their text.

Command and AltCommand

Both of these properties take a string of code that will be evaluated at certain points. For example, the GuiButtonCtrl calls the command when it is clicked. Most controls don't use both command and altCommand. Generally, the command is code that is called during the use of the control, whereas altCommand is called when the control is done being used. But there are no hard rules here! Just two commands that each control can use as they see fit. See the detailed section below for each control to see which command you should set.

Accelerator

The Accelerator Key gives you an easy way to set a key that will activate the control. What that means exactly depends on the control. A button control for example will simulate a click. If another control absorbs a key press nothing will happen. This basically give you an easy way to build hot keys into your GUIs.

GuiControlProfile

This class is not actually a GuiControl. Instead it holds a handful of common values that each control uses to render itself. Here is a list of all of those properties. Most controls won't use all of these properties and you'll want to go the section for the control in question to see exactly which properties should be set for a control.

  • tab - True if the tab key can be used to access the control.

  • canKeyFocus - True if the control can be given keyboard focus.

  • mouseOverSelected - True if a control becomes "selected" when the mouse is over it.

  • modal - This generally only applies top level controls that are pushed onto the Canvas with pushDialog(). True means that it will allow events that it doesn't consume to pass to the dialog or screen below it in the stack. False means that it will consume all events. Sounds scary...

  • opaque - This is true if the object is not completely translucent. The fillColor will only be used if opaque is true. This does not affect border rendering. Defaults to true.

  • fillColor - Normally this is used for the background of the control.

  • fillColorHL - The HL stands for HighLight. This color is typically used when a control is hovered over. There are variations for font colors and borders that match this as well.

  • fillColorSL - The SL stands for Selected. Use of this color is control specific.

  • fillColorNA - The NA stands for Not Active. This color is used for disabled controls.

  • borderDefault - A GuiBorderProfile that is used for all four borders of a control. This can be overridden with more specific settings. See the next section for more details on a GuiBorderProfile.

  • borderLeft, borderRight, borderTop, and borderBottom - Profiles that can be used to override the borderDefault setting for a specific edge.

  • fontType - The name of the font that should be used by the control.

  • fontSize - You guessed it! The size of the font that should be used by the control.

  • fontColor - The color of the font.

  • fontColorHL, fontColorSL, and fontColorNA - The variant font colors for HighLight, Selected, and Not Active.

  • fontColorLink and fontColorLinkHL - As the name suggests, some controls use this to render links and HighLighted links.

  • fontCharset - Possible values are: ANSI, SYMBOL, SHIFTJIS, HANGEUL, GB2312, CHINESEBIG5, OEM, JOHAB, HEBREW, ARABIC, GREEK, TURKISH, VIETNAMESE, THAI, EASTEUROPE, RUSSIAN, MAC, and BALTIC.

  • align - Handles how the font is aligned. Possible values are left, right, or center.

  • vAlign - The vertical alignment of the font. Possible values are top, middle, or bottom.

  • textOffset - The offset of the text from the position that it would normally be rendered. This is typically applied after the text's position has been calculated. You should be careful not to move the text outside of the control or it will be clipped.

  • returnTab - True for certain controls will cause the return key to simulate a tab press.

  • numbersOnly - The control should only allow numbers. Mostly useful with text edit controls.

  • cursorColor - The color of the blinking text cursor in text edit controls.

  • bitmap - The name of the bitmap file to use for the control. Typically you would start this string with a carrot (^) followed by the name of the module and then the file path to the image. Many controls break this image into multiple pieces based on a separator color. The separator color can be any color and is determined by the color of the top left pixel in the image. The number of and configuration of the bitmap pieces needed are highly dependent on the control. See the section below for the control you're interested in. If you want the control to render without a bitmap then don't set this entirely. Setting it to an empty string will result in an error.

  • soundButtonDown - A sound asset that should be played when a button is pressed down. Obviously, not all controls will use this.

  • soundButtonOver - A sound asset that should be played when the cursor enters a control.

  • profileForChildren - The profile to use with children elements of the control (such as the scroll bar on a popup menu). This is only used in very specific cases.

GuiBorderProfile

These profiles can be assigned to a GuiControlProfile either as a default border profile that covers all sides, or as a profile that covers a specific side. This allows you to control the look of each side separately from the others. This also has variations for the different control states, allowing you to customize the way each control looks. The spacing used for borders mimics that of the CSS Box Model with margin on the outside, then borders, then padding and finally content.

  • margin, marginHL, marginSL, and marginNA - An integer state the size of the margin with state variations. The area of the visible control will be decreased by the size of the margin. Although nothing is rendered to the margin, it is still part of the control. So a button rendered with a margin of 10 will have an area 10 pixels deep around it that can still be clicked as part of the button. Because of this, you should use small margins for effect and use position and extent if you want to shrink and relocate the control.
  • border, borderHL, borderSL, and borderNA - An integer stating the size of the border with state variations. Use zero for no border.
  • borderColor, borderColorHL, borderColorSL, and borderColorNA - The color of the border with state variations.
  • padding, paddingHL, paddingSL, and paddingNA - An integer stating the size of the padding with state variations. The padding is the distance between the border and the content of the control such as text and child controls.
  • underfill - True if the control's fillColor should appear under the border. This really only matters if you decide to use partially transparent colors for your boarder.

Content or the Inner Rect

Occasionally in this guide, the content or inner rect of a control will be referred to. This means the area of the control after applying the margin, border, and padding for all sides. Both text and child controls are positioned with in the inner rect. So placing a child control at (0,0) will place the top left corner in the top left corner of the content. In most cases, you will want the inner rect to remain unchanged by the state variations. So for example, if you have a margin of 1 in the normal state and a margin of 0 when the control is hovered, then you should offset the change with a 1 pixel increase in border or padding when the control is hovered. This will keep text from moving around when the control changes states and keep child controls resizing in a consistent way.

List of Controls

Up to this point, we've covered in a general way how the Gui system works. This section will take an in depth look at each control. These are grouped with similar controls together. The most important controls come first.

GuiControl

All controls inherit from the GuiControl. In most cases, the only reason to use the GuiControl directly is as a container to hold other controls or to display single lines of text. The GuiControl renders using the standard fillColor and border settings. If you add text to the GuiControl then it will be rendered in the content section of the control. Here is an example of a plain GuiControl rendered over the Truck Toy.

GuiControl Example

GuiCanvas

The GuiCanvas is a very special control that sits at the root of the GuiControl tree. There is only one canvas: a named variable aptly called "Canvas". This is initiated through createCanvas(). The canvas can then set a GuiControl as its content and show additional GuiControls as dialogs. Details of all the functions available to the canvas can be found in the Doxygen documentation. A simple review of the code shows that the canvas does not use a GuiControlProfile at all. Like other controls, it uses position and extent.

SceneWindow

This is the only GuiControl that doesn't start with "Gui" so you know it's special! As it turns out, the concept of the SceneWindow is extremely important to developing with T2D which is why is already covered in the Getting Started Guide. To summarize, the SceneWindow is a GuiControl that renders a Scene to the screen. The various functions of the SceneWindow are covered by the Doxygen documentation.

The SceneWindow uses its profile's font and fontColor to render metrics. The background of the metrics banner uses the fillColor.

The position and extent of the SceneWindow is also important. When the extent of the SceneWindow changes, it will not adjust the camera area covering the scene. If the ratio of width to height for the scene does not match that of the camera then the image will appear stretched. To combat this, you should respond to the onExtentChange() callback and adjust the area of the camera to match the new extent.

MySceneWindow::onExtentChange(%this, %bounds)

The new bounds for the SceneWindow are passed into this callback. This is a space-separated string that contains positionX, positionY, width, and height.

GuiButtonCtrl

This is a common push button. There are several ways to handle clicks on the button, all detailed below.

Settings

  • command - The button evaluates the contents of the command string if the button is clicked or otherwise activated. If no command is given, the button instead will call the onAction() callback.

Callbacks

  • onTouchEnter() - Called when the mouse passes over the button.
  • onTouchLeave() - Called when the mouse leaves the button.
  • onTouchUp() - Called when the mouse button is released over the control.
  • onClick() - Called when the button is clicked, either with the mouse or with the accelerator key.
  • onRightClick() - Called when the right mouse button is released over the control.
  • onAction() - Called if no command is set after calling onClick().

Profile Fields Used

  • FillColor and Border - If no bitmap is given, the button is rendered in the same way as the GuiControl and uses fillColor and border settings to do that. However, unlike the GuiControl, the button will use the different states.
  • Tab - True allows the button to be selected using the tab key.
  • canKeyFocus - Will receive keyboard inputs first if this is true and the button is interacted with.
  • soundButtonDown and soundButtonOver - These sounds will be played if useMouseEvents is set to true.
  • align and vAlign - This will determine how the text is aligned within the button.
  • bitmap - A bitmap can be used to render the display of the control. Note that the control will still use the border size to determine text placement. If the bitmap has text on it, then be sure to leave the text field blank. For the bitmap to work, there must be a full 36 sections to the bitmap (9 sections for each of the 4 button states). The button states in order are normal, highlight, selected, and disabled. Here is an example magnified x4.

GuiButton Bitmap Example

As you can see, each section is divided by a red line. The dividing color is determined by the top left pixel. The corner images will not be stretched. The other images will be stretched to fit the size the button.

GuiCheckBoxCtrl

The checkbox inherits from GuiButtonCtrl. The information for that control still applies to the checkbox but it won't be repeated here. Checkboxes expand on basic buttons by allowing them to toggle on and off. With the right settings, the GuiCheckBoxCtrl could be made to look and work like a normal button with toggling.

Settings

  • stateOn - Set this to true to start the checkbox as checked.
  • boxOffset - The offset from the top left corner of the content that the actual checkbox should be rendered. Note that the entire control is still clickable.
  • boxExtent - The size in width and height of the actual rendered checkbox. Note that the extent of the box cannot go outside the bounds of the content.
  • textOffset - The offset from the top left corner of the content that the text area will begin. This has the same name as a field in the GuiControlProfile but is functionally different.
  • textExtent - The width and height of the area that the text will be rendered in. Note that the textExtent will not expand outside of the control's content.

Callbacks - Has the same callbacks as GuiButtonCtrl.

Profile Fields Used - Uses the same fields as GuiButtonCtrl.

  • bitmap - A bitmap can be used to render the checkbox. The bitmap will only apply to the boxOffset and boxExtent. The checkbox requires a bitmap with six frames. The frames are off, on, off hover, on hover, off disabled, and on disabled. Here is an example magnified x4.

GuiButton Bitmap Example

GuiRadioCtrl

The radio button inherits from GuiCheckBoxCtrl so the information about that control applies to the radio button as well. Radio buttons stay on when clicked, but only one radio button in a group can be on at a time. Default rendering for radio buttons render them as circles instead of squares.

Settings

  • groupNum - Radio buttons of the same group should have the same groupNum. When one button is clicked, the other buttons in the same group turn off (they "radio" to the other buttons that they should turn off).

Callbacks - Has the same callbacks as GuiButtonCtrl.

Profile Fields Used - Uses the same fields as GuiButtonCtrl.

  • border - Since radio buttons are rendered as circles, they only have one border. As such, only the borderDefault value is used. The more specific settings, like borderLeft, are ignored.
  • bitmap - A bitmap can be used to render the radio buttons. The bitmap will only apply to the boxOffset and boxExtent. Like the checkbox, the radio button requires a bitmap with six frames. The frames are off, on, off hover, on hover, off disabled, and on disabled. Here is an example magnified x4.

GuiButton Bitmap Example

GuiTabBookCtrl

Everybody knows how tabs work! This control adds tabs to the GUI system. The GuiTabBookCtrl is the main control that is responsible for keeping a list of "pages" and rendering tabs for them. Clicking on the tab switches to the page. Easy right? Tabs can be position on the top, bottom, left or right and have a wealth of rendering options.

Only a GuiTabPageCtrl can be added to the book as a child. To work as intended, the page should have the same extent as the book and be positioned at (0,0). The page and its contents will then be resized to fit the page area when the page is added to the book. For this reason, it is important that the contents of the page are added before the page is added to the book.

Settings

  • tabPosition - The location of the tabs. Possible values are top, bottom, left or right.
  • tabProfile - This is a GuiContentProfile. In addition to the normal profile, which applies to the area behind the tabs, this profile is used to render the tabs themselves.
  • minTabWidth - This is the smallest a tab can shrink.

Profile Fields Used - In case you missed it, this control has two profiles: profile and tabProfile! The normal profile's border and fill color is applied to the area behind the tabs. This allows you customize the background. Only the normal state is used so don't both setting the other states (i.e. set border but don't bother with borderHL). The tabs are rendered in the inner rect of the profile. So adding padding to the top border of the profile will add some space between the tabs and the top of the tab section. The tabProfile is applied to the tabs. This includes the fill color, font settings, and border settings with all states. Bitmaps cannot be used yet.

Methods

  • selectPage(%pageIndex) - Selects the active tab by a zero-based index.
  • selectPageName(%pageName) - Selects the active tab by the name that appears on the tab. This is the text or textID field inherited from GuiControl.

GuiTabPageCtrl

The only possible child control of the tab book above. The GuiTabPageCtrl is basically a special container. It's profile is used to render the page section of the tab book when the page is active. The page should be set to use the entire area of the book and will be resized as needed. The text set on this control will be used in its matching tab. Here's an image to recap how the book and page work together.

GuiButton Bitmap Example

Settings

  • text or textID - These are inherited from GuiControl, but it's worth noting that the page control uses these values to display the text on the actual tab.

GuiScrollCtrl

This control is a simple container with scrollbars if the contents happen to overflow the container. The control's profile will be applied like other controls with margin on the outside, then the border, and last the padding. The actual scrollbars will appear between the border and the padding and the padding will appear within the scrolled area between the child controls and the border. Child controls should always be placed at positive coordinates. The scrollable area will not extend to the left or top past zero.

Some quick terminology: The scrollbar has arrow buttons on either end of it. The moving part between the arrow buttons is called the thumb. The thumb moves along the track.

Settings

  • scrollBarThickness - Determines the width or height of a scroll bar. Since the bar is controlled by profiles (more on that later) this represents the thickness of the entire scroll bar including any margin, border, and padding. The scrollbar may not render correctly if these three are greater than the thickness. The arrow buttons are always a perfect square based on the thickness and the thumb will be two times the thickness if constant thumb height is used. If a bitmap is used, then this value is overwritten by the width of the vertical track frame. Defaults to 16 pixels.
  • showArrowButtons - If false the arrow buttons will be hidden entirely. Hiding arrow buttons is a common trend in modern applications, but some users prefer to have them available. Defaults to true.
  • constantThumbHeight - True if the thumb should be a constant size regardless of scroll area. Thumb will be twice the thickness in this case. If false then the scrollbar will reflect the size of the scroll area.
  • hScrollBar and vScrollBar - Determines if these bars are visible. Possible values are alwaysOn, alwaysOff, and dynamic. Dynamic scrollbars will only appear if the contents of the container overflow the content area. If always on and the children fit in the contents, then the bar will appear but will be disabled using the profiles' disabled states. Defaults to alwaysOn.
  • thumbProfile - This is the GuiContentProfile that will be applied to the thumb and arrow buttons. This profile is required unless there is a bitmap given.
  • trackProfile - This is the GuiContentProfile that will be applied to the track. This profile can be ignored if you prefer an invisible track. It will be ignored if a bitmap is given.
  • arrowProfile - This is the GuiContentProfile that will be applied to the arrow buttons. This profile is ignored if the arrow buttons are hidden using showArrowButtons. It is required otherwise, unless a bitmap is used.
  • bitmap - If a bitmap is supplied in the main profile, it will be used to render the scrollbar. The provided bitmap must have 39 frames which represent 13 parts of the scrollbar in 3 different states; normal, selected, and disabled. Notice that the highlight state normally used to show that a control has the mouse hovering over it is missing. This might be added at a later point. For now you'll have to use profiles if you want this behavior. The 3 states directly follow each other in the bitmap so for example, the first three frames should be the up arrow in the three states. The 13 parts of the scrollbar are the up arrow, down arrow, vbar top cap, vbar center, vbar bottom cap, vertical track, left arrow, right arrow, hbar left cap, hbar center, hbar right cap, horizontal track, and the corner.

Profile Fields Used The scrollbar has four different profiles! The main profile applies to the body of the control and includes the margin, border, and padding in the normal state. Fonts and other states are ignored. The trackProfile uses the margin, border and padding of the normal and disabled states. The arrowProfile and thumbProfile both use the margin, border, and padding of all four states. Additionally, the arrowProfile uses the font colors of the four states to color the arrows which are drawn within the content of the arrow buttons.

Methods

  • scrollToTop, scrollToBottom, scrollToLeft, scrollToRight, and scrollToPosition - Allows you to change the position that the content area is scrolled to.
  • getScrollPositionX and getScrollPositionY - Returns the indicated scroll position.
  • computeSizes - This is a function used internally by the control to position everything correctly. It is exposed here incase you need to refresh the contents of the control. It is unlikely you'll need this.
Clone this wiki locally