Game Development Community

dev|Pro Game Development Curriculum

Gui Learning Project

by Evan Ogawa · 02/16/2007 (9:20 am) · 3 comments

Download Code File

Documentation
The code file should have a number of web pages (that I had created and posted to TDN) documenting various classes related to this article.

Installation and Running
First download the code file, a PKzip archive of the game's directory (not packaged; full source is provided). Place the game directory in your TGB directory along with your other projects. Launch TGB and File->Open Project, select GuiLearningProject.

In the Level Editor, select File->Open Level. In the file selection dialog, expand GuiLearningProject->data->Levels. On the right side of the dialog, you will see GuiProject.t2d. Open this.

You will notice in the Level Editor that there is practically no level at all(!). That is because this project is all Gui. Run the game (Project->Run Game).

You see a number of windows, with titles like GuiControl, GuiTextEditCtrl, and GuiBitmapButtonCtrl. Each one represents a self-contained world where that partcular Gui class is being investigated. Each window can be moved, resized, and minimized. So go ahead and minimize all except the one titled GuiControl.

GuiControl
shows a rectangular region (framed by a thin black line) with an oddly colored rectangle partly overlapping a bitmap button labeled ReorderChildren. Yes, that oddly colored rectangle is the GuiControl under investigation (in fact, its name is GuiControlUnderTest). All of the other controls in the window change it in various ways. Each of the methods of class GuiControl and each of its member fields is used in a non-trivial way, so you can understand how the class works in context.

At the very top of the window is a status line. Down below to the right is the group giving access to the ToolTip text and hover time. Below that is the group of controls for our GuiControl's Position. Still further down is the corresponding Extent group for its size (extent), and between the two is a group Resize that allows you to change position and size at once.

On the left is a group for setting HorizSizing and VertSizing (explanation below), below that is the Value group, and further down is a group of four booleans.

These control groups represent collections of methods and members of class GuiControl, and once you master them all, you are well on your way to mastering other GuiControl classes. Why? Because GuiControl is the base class for all Gui Controls! Our other learning windows for other classes will not deal with these methods and members; instead, they concentrate on the particular methods and members of the respective class.

Let us start our investigations by moving and resizing the control.

You can use the sliders to adjust the position and size (AKA extent). In each pair, the top slider is for horizontal, the bottom for vertical. You can also set position and size by typing numbers into the text edit boxes. Play! (Don't worry, you cannot get into trouble!)

You will notice two constraints on the rectangle. One is the minimum size, which is set by the MinExtent member variable. The other is that the rectangle is not allowed to escape its parent control's region. The first constraint is imposed by TGB itself.

The second constraint is implemented in the script, mostly to prevent the control from escaping our sight. You would not have to do this in your own code, of course.

You will also notice that all of the controls update in concert, maintaining consistency. You can use the number in the controls to understand the relationship between the local and global coordinates.

ToolTip
Now that we can put that rectangle anywhere we want, we can do a little ToolTip investigating. Start by putting the control as far to the left as possible (set Position to "0 0").

You can change the text of the tooltip dynamically. Just type whatever you want into the text box of the ToolTip group and press "enter". Did you press "return" instead? No, that will not work; you must press "enter", I assure you.

Now when you hover the mouse over the control, the ToolTip's text reflects your change. How nice.

The next step is to change the hovertime. There is a gotcha here, though. The hovertime does not come into play if you have been triggering tooltips with frequency. So set the slider or type in your number (in milliseconds) and move the mouse right out of the application window.

To get the ToolTip mechanism to calm down, bring up the Console (~) and then put it away. No tooltips are showing, right? Now quickly move the mouse from left to right into the rectangle and wait those milliseconds away. Bingo! Was the time correct? If the tooltip came on immediately, you will have to try again. Life gets a bit difficult when you change the hovertime of a single tooltip out of many. The others tend to trigger the mechanism early. Oh, well. At least we know we can do it if we want.

Booleans: Visible, Active, Awake, CanSave
Let us turn to the boolean checkboxes.

Visible signifies whether the control is, uh, visible. Switch the checkbox off and on, and you will see the rectangle vanish and reappear. But it was there all the time!

Active signifies whether the control can be used for user input. Now, the base GuiControl class does not provide any such functionality, so this checkbox is rather pointless. But the code is working properly behind the scenes. When we go to play with a control for which Active makes a material difference, we will come back to this feature.

Awake signifies that the control is present in a Gui (like our GuiControlUnderTest is present in that larger rectangle) or set as the content of a Canvas (like our mainScreenGui). If we remove the control from the parent, it will vanish, and it really will not be there. So uncheck the box and notice that the control vanishes. Then check the box and it shows up. But, check the console log, too! There you will see that the control has executed its onWake() callback. Yay! (You always wanted to see that in action, didn't you?)

CanSave signifies that our control is allowed to serialize itself to a file during a SimObject.save() operation (this operation is recursive, so the save() could come from anywhere up the container tree.) For now, you can just check and uncheck it. Perhaps in future we can add a pushbutton to Save this control and you will see how the innards work.

Value is the value associated with the control. A slider has a value, as does a text control, a popup menu, and so on. However, a GuiControl object does not implement setValue() and getValue() semantically (the functions are defined, but they do nothing). Sorry. We will come back to Value in other controls.

HorizSizing and VertSizing determine how the control's size and position will behave when the parent control is resized. Each has five enumerated alternatives. Here is where you take advantage of the window's ability to resize. Do this and note the behavior of the control in each of the five alternatives.

right-signifies that the right edge of the control is not constrained, but the left edge maintains a fixed distance from the left edge of the parent. The width of the control therefore varies as the parent control resizes.

left-is the opposite of right.

top and bottom-are defined in a similar way, but for the vertical dimension.


center-signifies that the center of the control is aligned with the center of the parent. The width does not vary.

relative-while parent size increases, height is proportional to that of parent; while parent size is decreasing, control size is fixed. This is pretty strange behavior; it, ahem, almost looks like someone fell down on this one.

Moves and Clicks
We get to mouse around on the Gui! Start by placing the control's rectangle so that it overlaps the button somewhat. Next, make note of the status line at the top of the screen. Now move the mouse around within the parent window.

In the status line, you will see three Vector2I values forming an equation: World - Global = Local. The first, World, signifies the mouse position in the coordinate system of the Canvas (origin is the Canvas upper left corner). The second, Global, indicates the World coordinates of the parent (its own upper left corner). The third, Local, gives the mouse position relative to the upper left corner of the parent control.

The status line also shows inControl and inButton along with their (boolean) values. The first signifies that the mouse is within the control's rectangle, the second, for the button. You are seeing the result of repeated calls to pointInControl() (called from the onMouseMove() callback).

You will also note that where the control's rectangle overlaps the button, the former appears to be on top of the latter.

Now, click somewhere within the button, but not within the control. You will see the button is now in front of the control. Click the control, and it returns to the front. Click in the overlap, and they toggle. You are changing the order of the controls in the parent's SimGroup with pushToFront(), sendToBack(), and reorderChild(). Fun!

We have complete our overview of the GuiControl playground. Quit the game and return to the Level Editor.

Examining the Gui

Launch the Gui Editor (Project->Gui Builder). From the center PopDown menu, select mainScreenGui. You see where all the action is in this project.

Feel free to roam in the Gui; pay particular attention to the Command and AltCommand member fields of the various controls. It is here that the connection to the GuiControlUnderTest lies.

Examining the code

In your favorite development environment or text editor, open ./gui/mainScreen.gui and all of the files in ./scripFiles. Among the latter are:

GuiControlUnderTest.cs - This is the class for the GuiControl we are playing with. It shows many examples of use of the methods and member fields of that class. The other controls in our window call the methods of this class.

GuiControlMouseEvent.cs - This class manages the GuiMouseEvent object we use in our window. We track the mouse so we can illustrate pointInControl() and we monitor clicks so we can re-order the child controls, one of which is GuiControlUnderTest.

SizingPopup.cs - Provide the popup menus for HorizSizing and VertSizing. Good example of a static GuiControlListPopUp.

GuiBitmapButtonCtrlUnderTest.cs - A start on exercising the class GuiBitmapButtonCtrl and GuiBitmapButtonTextCtrl. Not very much fleshed out.

mainScreen.gui - Contains, of course, the Gui that Canvas.setContent() loads up. You will find each of the GuiWindowCtrl objects, WindowForGuiTextEdit, WindowForGuiBitmapButtonCtrl, and WindowForGuiControl.

It is here that the GuiControl's member field Profile and method setProfile() are definitively exercised. We have a facility that in future will be used to illustrate the usage of each of the 46-some member fields of GuiControlProfile.

We also have a custom profile for our GuiControlUnderTest: its name is GuiControlUnderTestProfile, establishing a convention that we will take advantage of in future work. Feel free to play around with the fields and values of that custom profile.

You can also invoke the function changeControl_param_value( %object, %param, %value ) from the console. A sample usage might be:
changeControl_param_value( GuiControlUnderTest, "fillcolor", "200 90 230 64" )
to turn the control into yet another macabre color.

To Come

Discussion of the other windows (GuiTextEditCtrl, GuiBitmapButtonCtrl).

More windows with more controls.

[email]arthur_ogawa at teleport.com[/email] would like to hear from you if you have feedback on this Code article.

About the author

Recent Blogs


#1
04/08/2009 (6:46 pm)
Is anyone else not seeing any project file in this or am I just missing something horribly?
#2
07/20/2009 (6:11 am)
Same for me. I can not find the project file
#3
07/20/2009 (6:24 am)
In fact, I have create a new project and replace the file by the downloaded one.