Script GUIs

Scripted GUIs can be used to create menus, HUD elements and scoreboards.

Eigenschaften

(For a detailed explanation and examples, see below.) Every window can be defined by the following properties, which can additionally be tagged:
Name Datentyp Beispiel Beschreibung
ID int 2 The ID of the window. See below.
Target object GetCursor(0) The target of the window. See below.
Left string "0%" (default) The left corner of the window. See below.
Top string "0%" (default) The top corner of the window. See below.
Right string "100%" (default) The right corner of the window. See below.
Bottom string "100%" (default) The bottom corner of the window. See below.
Margin array ["1em", "1em"] Margin around the window; used for layouts. The order is [left, top, right, bottom and will wrap around. You can specify all margins by giving only one item (f.e. ["1em"]) or the X and Y margins by giving two items (f.e. ["1em, "0em"]).
BackgroundColor int RGBa(255, 0, 0, 128) Solid background color of the window. The value 0 means no background color.
Symbol object/definition Clonk A symbol that will be drawn in the window. The symbol can be an object as well, in this case the current graphics and animations of that object will be drawn.
GraphicsName string "Infinite" Only if Symbol is a definition: the name of the graphics to use.
Decoration definition GUI_MenuDeco Menu decoration of the window. The menu decoration can be defined as for CustomMessage().
Text string "Hi there!" Text that will be drawn in the window. The window's height will be adjusted to fit all the text
Tooltip string "Buy Loam" Tooltip of the window.
Style int GUI_TextVCenter Combination of style-flags. For possible values, see below.
OnClick array GuiAction_Call("GameOver") Action that will be executed when the window is clicked, see below.
OnMouseIn array GuiAction_SetTag("Hover") Action that will be executed when the cursor enters the window, see below.
OnMouseOut array GuiAction_SetTag("Std") Action that will be executed when the cursor leaves the window, see below.
OnClose array GuiAction_Call("RemoveHelper") Action that will be executed when the window is closed, see below.
Priorit├Ąt int 1000 Priority of the window that is used for layouts and for the drawing order. Higher number means higher priority.
Spieler player number GetOwner() If given, the window is only visible to this player. Note that the target object also restricts visibility.
All other properties are proplists that define sub-windows. You should use non-capital names (i.e. header, not Header) for your sub-windows.
The names of your sub-windows properties can also be used in updates when you want to update properties in both a parent window and a child window. Names starting with an underscore (e.g. _child) are anonymous. That means that they can not be referenced by their name later and will not be overwritten by an update that uses the same name again. This can be used to add several new windows later without having to care for duplicate names. For an example, see GuiUpdate().

Style Flags

Every window can have a combination of style flags as the Style property.
Name Beschreibung
GUI_Multiple Only one window without this flag will be shown at a time, can be used to show multiple HUD elements using the GUI.
GUI_TextVCenter The text will be centered vertically.
GUI_TextHCenter The text will be centered horizontally.
GUI_TextRight The text will be aligned to the right.
GUI_TextLeft Default. The text will be aligned to the left.
GUI_TextTop Default. The text will be at the top.
GUI_TextBottom The text will be at the bottom.
GUI_GridLayout The sub-windows of this window will automatically be arranged in a grid.
GUI_TightGridLayout Like GUI_GridLayout but might reorder items and lead to less empty space between sub-windows.
GUI_VerticalLayout The sub-windows of this window will automatically be arranged vertically in a list.
GUI_FitChildren The window will adjust its height to fit the sub-windows. No scroll-bar will be shown.
GUI_IgnoreMouse No mouse-input will be used for this window. The window will not block mouse clicks to the landscape behind.
GUI_NoCrop Children of this window may be drawn outside the window's bounds. Text in this window set with the Text property will not automatically be broken into multiple lines. Note that clipping is only performed for subwindows, not root windows.
For example multiple Style elements can be combined as: Style = GUI_Multiple | GUI_TextVCenter | GUI_TextHCenter

The Window Concept

The whole menu system is basically just a way to display rectangles on the screen and react to events (clicks, mouse-over) that affect those rectangles. Every rectangle (now called windows) is defined by a proplist. Every property is either one of the attribute-properties which always start with a capital letter or defines a sub-window.

A Window ID

For certain features, the scripter needs to be able to identify windows. This may be important to either react to events affecting certain windows or to update windows after the initial creation. Window IDs can be assigned using the property ID, but only together with the property Target (which stands for an ingame object) does an ID identify a window! This is important to allow the easy creation of menu libraries and pluggable-submenus which do not have to care for unique IDs that way. All callbacks coming from a window or updating a window will always take both a target and an ID. Aditionally, a window inherits the visibility of the target object and is destroyed when the target object is removed. Note that nil is a valid Target for all interactions. But if you are writing a library or a menu interface, you should consider giving your menus proper targets if they need to interact.
When you open your menu via GuiOpen() you get another ID, which is the ID of your root window that you cannot set yourself. You use that ID when you interact with the already opened GUI - for example when you want to close it, for an example see GuiClose().

Coordinates

A window can have four properties to define its position: Left, Top, Right, Bottom. The coordinates are given as strings in percent of the parent window. The properties Right and Bottom define the position of the right and bottom border of the window and not the width and height. The definition to have a window cover the right half of its parent would look as follows:
func MakeMyMenu()
{
	var menu =
	{
		Left = "50%",
		Top = "0%",
		Right = "100%",
		Bottom = "100%",
		...
	};
	var menu_id = GuiOpen(menu);
	
	// I made  up my mind, I'd rather not have a menu.
	GuiClose(menu_id);
}
While the relative positioning is prefered, windows can also have an absolute position that is added to the relative position. Imagine you would want to add fixed-size images below and on the left of the previous menu:
func MakeMyMenu()
{
	var menu =
	{
		Left = "50% + 3.5em",
		Top = "0%",
		Right = "100%",
		Bottom = "100% - 3.5em",
		...
	};
	GuiOpen(menu);
}
The unit of the absolute values is in em - 1em is exactly the height of the font, so a text box of 2em height can always contain two lines of text. For both the relative and the absolute values, you can provide decimal numbers (f.e. Left = "10.5321% - 1.3333em").
Especially if you need to do some math with the positions, there are some interesting helper functions defined for you in System.ocg/GUIs.c.

Positioning Example

Here is an example with a screenshot that details in what margins the given positions will result.
func MakeMyMenu()
{
	var menu =
	{
		Text = "I am the container!",
		BackgroundColor = RGB(255, 255, 100),
		rightbottom =
		{
			Text = "I am at the bottom right",
			BackgroundColor = RGB(100, 255, 255),
			Left = "25% + 6em",
			Top = "25%", Bottom = "90%",
			centerbottom =
			{
				Text = "I might be a text box",
				BackgroundColor = RGB(255, 100, 255),
				Left = "10%", Right = "90%",
				Top = "100% - 5em", Bottom = "100%"
			}
		}
	};
	GuiOpen(menu);
}

The result of the example code above.
In the screenshot the GUI debugging info is activated, too. You can reach it via hitting CTRL+F7 multiple times.

Tags for Properties

Nearly all properties can be tagged - that means they can be assigned different values for different tags. The default tag for every window is Std. To assign multiple values for different tags, just assign a proplist instead of the original property value, such as:
BackgroundColor = 
{
	Std = RGB(255, 0, 0),
	Hover = RGB(0, 255, 0)
}
instead of BackgroundColor = RGB(255, 0, 0)
To change the tag of a window use GuiUpdateTag() or GuiAction_SetTag(). When you change a tag, the change usually also affects the children of the window. Note that the window ID and Target can not be tagged.

Actions

To make the player able to interact with the windows, actions can be defined that are executed on a certain event. Possible events are for example OnClick, OnMouseIn, OnMouseOut. Possible actions are GuiAction_Call() and GuiAction_SetTag(). An example:
func Initialize()
{
	var menu =
	{
		BackgroundColor = 
		{
			Std = 0,
			Hover = RGBa(255, 0, 0, 200)
		},
		OnMouseIn = [GuiAction_SetTag("Hover"), GuiAction_Call(this, "Hovering", "I am a parameter")],
		OnMouseOut = GuiAction_SetTag("Std"),
		OnClick = GuiAction_Call(this, "ClickedMyMenu")
	};
	GuiOpen(menu);
}

func Hovering(data, int player, int ID, int subwindow_ID, object target)
{
	Log("Player %d is hovering on my menu.", player);
	Log("The custom parameter was: %s", data);
	// output "The custom parameter was: I am a parameter"
}

func ClickedMyMenu(data, int player, int ID, int subwindow_ID, object target)
{
	Log("Player %s clicked on my menu! Blowing up something..", GetPlayerName(player));
	var clonk = FindObject(Find_OCF(OCF_Alive), Find_Not(Find_Owner(player)));
	if (clonk) clonk->Explode(20);
}
Zapper, 2014-10