Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The static ModalRoot and PopupRoot properties provide an InteractiveGue which serve as the root for any element which should appear on top of other elements. These properties have the following characteristics:
Automatically created by FormsUtilities.InitializeDefaults
Automatically resized to fit the entire screen, including if the GraphicalUiElement.CanvasHeight
and GraphicalUiElement.CanvasWidth
change.
Both Remains on top of all other elements for its given layer. ModalRoot appears on top of PopupRoot.
These properties can be used in custom code to place elements (such as custom popup and toast elements) above all other elements.
ModalRoot and PopupRoot are used internally by Gum Forms. For example PopupRoot is used to display the ListBox which appears when expanding a ComboBox.
Popups which are placed on the ModalRoot element are considered modal - they block the input of all other controls. This is useful if you would like to create a popup which must be clicked before any other elements receive input. If multiple elements are added to ModalRoot, only the last item (and its children) receive input events. This allows one popup to show another popup.
By contrast, elements added to the PopupRoot are not modal - other elements can receive input.
The ComboBox control normally places its expanded form ListBox on PopupRoot; however if the ComboBox is on a ModalRoot then its ListBox is also added to ModalRoot.
The following code can be used to display a popup to either ModalRoot or PopupRoot depending on the isModal
value.
The IsFocused property gets or sets whether a component has focus. For example a TextBox will have its IsFocused set to true if the caret is visible and if it is taking input from the keyboard.
IsFocused can be directly assigned to give focus to an object. For example the following code gives a TextBoxInstance focus:
If you are setting focus on a TextBox in response to a click event, you may need to also clear the Cursor's input. For example, the following would set focus on TextBoxInstance when ButtonInstance is clicked:
The ListBox control provides a scrollable list of ListBoxItems for displaying and selecting from a list.
The following code adds items to a ListBox when a button is clicked. When an item is added, ScrollIntoView
is called so the item is shown.
ListBox items can be selected. The ListBox class provides a number of ways to work with the selection.
Selection can be set by index:
Item can also be selected by the reference itself, assuming the referenced item is part of the list box:
Whenever the selection changes, the SelectionChanged event is raised:
The VisualTemplate lets you customize the type of ListBoxItem created for the ListBox. The following code shows how to assign a VisualTemplate to a runtime object named CustomListBoxItemRuntime:
The VisualTemplate class can optionally pass a parameter representing the item in the list box. This can be used to create different types of items based on the object added. For example the following code would compare the passed object as an integer to whether it is greater than 100 and returns a different item depending on this result:
Note that the code above uses the item to decide which type of list box item to create. If your list box item needs to react to changes on the item, you can also pass the item in the constructor to your list box. This allows for additional initialization based on the item. You can also hold on to the reference of the item to react to changes that may happen on the item, or to push changes to the item.
In other words, you are free to use the item for your game's needs; however, keep in mind that UpdateToObject will be called after your ListBoxItem is constructed. For more information on how to customize UpdateToObject, see the section below.
By default the ListBox calls ToString on each item. This is usually okay if you are dealing with primitive types. For example, the following code adds sequential integers to a ListBox:
Often you may want to add a list of items which should not use their ToString method. For example you may have a list of IDs which represent weapons in a dictionary. The display can be customized by inheriting from ListBoxItem as shown in the following code:
Gum Forms is a set of classes which provide fully-functional forms controls which you can use in your game. Examples of forms controls include:
Button
Checkbox
ListBox
TextBox
Slider
Gum Forms can be used purely in code (no .gumx project required), or you can fully style your forms objects in a Gum project.
The easiest way to add Forms to your project is to use the FormsUtilities
class. Keep in mind that Forms is not a replacement for Gum; rather, it adds objects on top of Gum which provide common UI interaction. In other words, if you are using Forms, you are still using Gum as well. Therefore, when using Forms you must also initialize Gum.
The following code snippet shows how to initialize Forms and Gum, and how to add a single Button to your project:
The code above produces a single button which can be clicked to increment the click count.
Forms can be used with the Gum tool, allowing you to create fully functional UI layouts visually.
To use Forms in a project that loads a Gum project (.gumx) the following steps are needed:
Components must be added to the Gum project which have the necessary behaviors to be used as Forms visuals
The Gum project must be loaded in code, just like any other Gum project
To add components which are used for Forms visuals:
Open your project in Gum, or create a new project
If creating a new project, save the project in a subfolder of your game's Content folder
Select Content -> Add Forms Components
Check the option to include DemoScreenGum, or alternatively add a new screen to your project and drag+drop the desired components into your screen
Once you have saved your project, modify your Gum file to include the project:
Open your .csproj in a text editor (or click on it in Visual Studio)
Add the wildcard addition code to copy all of your Gum projects
Your project is now referenced in your game. Modify the Game file to initialize the Gum systems and to load the .gumx project. Your code might look like this:
The ScrollViewer control provides a container which can hold Gum objects (including other Gum Forms objects). The user can scroll the ScrollViewer with the mouse or ScrollBar.
By default the ScrollViewer's InnerPanel expands automatically in response to its children and stacks its children top-to-bottom. Of course, this behavior can be changed since the InnterPanel is a standard GraphicalUiElement.
The following code creates a ScrollViewer and adds ColoredRectangleRuntimes to the ScrollViewer.
VerticalScrollBarVisibility controls the visibility of the vertical scroll bar, specifically in regards to the number of items in the ScrollViewer. The available values are:
Auto - the ScrollBar displays only if needed based on the size of the inner panel
Hidden - the ScrollBar remains invisible even if the contents of the inner panel exceed the size of its container
Visible - the ScrollBar always displays
The default is Auto which means that the scroll bar only displays if necessary.
The TextBox control allows users to enter a string. It supports highlighting, copy/paste, selection with mouse and keyboard, and CTRL key for performing operations on entire words.
The following code creates a TextBox.
Selection can be performed programmatically or by the user using the cursor.
The SelectionLength
property can be used to determine if any text is selected. The following code shows how to output the selected characters:
The SelectionStart
and SelectionLength
proerties can be modified to change the visual selection. For example, the following selects the first 5 letters:
The entire text can be selected as shown in the following code:
Selection can also be performed by the user. Double-clicking the text box selects all text.
A push+drag with the mouse selects the text between the start and the current location of the drag.
Holding down the shift key and pressing the arrow keys adjusts the selection.
The TextWrapping property can be used to set whether the TextBox wraps text. By default this value is set to TextWrapping.NoWrap
which means the text does not wrap, but instead extends horizontally.
If TextWrapping is set to `TextWrapping.Wrap, then text wraps to multiple lines. Note that usually this is combined with a taller text box so that multiple lines display properly.
The PasswordBox control is a TextBox-like control which can be used for entering passwords. It uses a SecureString
rather than regular string
and hides the entered characters by using the *
key for each character typed. For more information see the SecureString documentation:
The following code adds a password box.
The Slider control provides a way for the user to change a value by dragging the slider thumb.
The following code creates a Slider which allows the user to select a value between 0 and 30, inclusive. The IsSnapToTickEnabled
property results in the value being snapped to the TickFrequency
value. In this case, the value is used to force whole numbers.
Gum Forms provide fully functional controls with minimal setup. These controls can be restyled in code, either per-instance, or globally per control type. Customization can be performed in-code or in the Gum tool.
Individual instances can be customized by modifying the built-in states which are added automatically by the default implementations.
Note that all code in this document assumes that Gum Forms has already been initialized.
The following code shows how to modify a Button instance. A default button can be constructed using the following code:
Notice that this button has subtle color changes when the cursor hovers over or pushes on it.
These cursor actions result in different states being applied to the button. These states are initialized by default when calling the following code:
We can customize the state by modifying the values. For example, we can change the color of the background by adding the following code:
Now the button highlights yellow instead of a lighter blue.
Each Forms instance creates its own Categories dictionary, so modifying the Categories on one instance does not affect the Categories on another instance.
Any property on the button or its children can be modified through states. For example, we can also change the text color and size as shown in the following code. You may need to make the button bigger so it can contain the larger text.
The button text now becomes black and is twice as big when highlighted but notice that the text changes are not undone when the cursor moves off of the button (when the Highlighted state is unset).
The reason that the hover state is not unset is because all variables which are set through states persist until they are undone. Typically if you create states in the Gum tool, the Gum tool forces any state which is set in a category to also be propagated through all other states in the same category. However, when we're setting states in code, we must make sure to apply any states that we care to all other categories.
In this case we can fix the larger text by setting the TextInstance's color and FontScale back to its default:
Each default control type is made up of individual instances, most of which are standard types such as ColoredRectangle and TextInstance. The example above assigns properties on two instances:
ButtonBackground
TextInstance
Since each control (such as Button, CheckBox, or TextBox) has its own individual instances, we need to know the names and types of these instances to add VariableSaves to our states.
We can find the names of these instances by looking at the source code for the default forms implementations.
These can be found in the Gum repository here:
For example, we can look at the DefaultButtonRuntime.cs file and notice that it has a ButtonBackground and TextInstance:
By inspecting the code of other controls we can see which instances are available for styling. We can also look at the existing states which are provided by the default implementations. For example the DefaultButtonRuntime adds states for Enabled, Highlighted, Pushed, and Disabled. Note that this list may change in the future as Gum Forms continues to be developed.
Keep in mind that the Name property of the internal instances is important. For example using the code above, the background object is accessed through "ButtonBackground" rather than "background" when creating new states.
The example above shows how to replace styling on a single Button instance. Instead of changing each instance manually, we can create a derived class which defines its own custom styling.
The first step is to create a new class which inherits from the default Forms control. These can all be found in the DefaultVisuals page linked above.
For example, we can create a derived class which inherits from the base DefaultButtonRuntime as shown in the following code:
Notice that we must implement a constructor with the same parameters as the base class - this is important because Gum calls this constructor for us when we create a Button instance and the parameter list must match.
Now we can implement our own styling inside the if(fullInstantiation)
block. The code to implement styling here is the same as above except this object is the visual, so the category exists on this
. For example, we can make the background pink when highlighted and enabled as shown in the following code:
Next we need to tell Gum Forms to use our new button as the default Button type. We can do this by replacing the default type associated with Button
as shown in the following code. This code should go in Game1 right after FormsUtilities.InitializeDefaults();
, before instantiating any Buttons as shown in the following code:
You may want to also remove or comment out any code for customizing the button explicitly below otherwise your pink styling may get overwritten on the particular instance by the styling written earlier in this tutorial.
By instantiating a Button
, Forms automatically uses your new StyledButtonRuntime
resulting in the button appearing pink.
The section above shows how to customize a button using inheritance. This approach is beneificial if you would like to modify the styling colors on the existing children of the button. Since Gum visuals are regular Gum objects, you can achieve even more customization by creating a new Button class which inherits from InteractiveGue and adding your own controls. In other words, you can add your own instances to the button (such as additional Text instances) or replace existing instances with your own (such as replacing the background ColoredRectangleRuntime with a NineSlice or Sprite).
For example, we can create a NineSlice that uses the following image:
Now we can create a new Button which inherits from InteractiveGue rather than DefaultButtonRuntime to fully customize the appearance of our button. Note that the only requirement that Buttons have is that they contain a Text object named TextIntance, so we should copy this instance from the DefaultButtonRutime code into our own. Our new Button also has a NineSlice which references the button_square_gradient.png from above, and states for Enabled and Pressed.
In general when creating your own Forms control, it can be helpful to reference the existing Default implementation for the control you are creating.
Of course we also need to tell Forms to use our new class as the default button type:
Now we can run our game and see the button in action:
As mentioned above, you are free to add any controls to your custom button including icons, additional Text instances, and additional Sprites for other effects. You can customize your Forms objects to look however you want.
Most controls in Forms share the same common states. The exception is components which can be toggled on/off such as CheckBox. For all other controls the following states exist:
Enabled
Disabled
Highlighted
Pushed
Focused
HighlightedFocused
DisabledFocused
CheckBoxes append the words On, Off, and Indeterminate to the states. For example, a CheckBox can support states including:
EnabledOn
EnabledOff
EnabledIndeterminate
DisabledOn
DisabledOff
DisabledIndetermate
... and so on.
Buttons can be defined fully in the Gum tool. This approach allows you to preview your visuals in the editor, and allows editing of the styles without writing any code.
Conceptually the steps are as follows:
Define a component for your forms type in the Gum tool
Add the states needed for the forms type that you are working with in the proper category
Define a custom runtime for the Forms control in your Visual Studio project
Associate the custom runtime to the forms type using the DefaultFormsComponents dictionary
This section walks you through how to create a custom Button component, and how to use this in your project. Once you understand how to create a Button component, other Forms controls can be created similarly.
The first step is to define a Button component in Gum. This component can be named anything you want. For example, you may name it Button or StandardButton. You can also create components for specific purposes such as CloseButton which would be a button that closes menus.
Components defined in Gum can contain almost anything you want; however, Buttons should usually contain a TextInstance so that the Text property can assign the string on an internal Text object.
The following image shows the a component named StandardButton which contains a ColoredRectangle, a Rectangle, and a Text instance. For other controls, see the DefaultVisuals page linked above.
All Gum Forms components react to various properties by assigning states. For a full list of states needed, see the DefaultVisuals page linked above.
Once you have created a Component in your project, you need to create a custom runtime class. This custom runtime class associates the Component in your .gumx file to a strongly-typed class. This runtime type also enables the creation of Forms controls by instantiating the runtime object, including when an element from the Gum project is converted to a GraphicalUiElement.
The runtime class does not need much code since most of the work is done in the Gum project. The following shows an example custom runtime for the StandardButton component:
This runtime can be associated with the StandardButton component in Gum using the following code in your Game class:
Finally, we can associate the Forms control with the runtime. For example, the following code can be used to create a StandardButtonRuntime whenever the code calls new Button
. Note that this is not a requirement for working with Forms, but it can make testing more convenient.
Note that in this case, we can only associate one type of component runtime with each type of Forms control. In other words, if you write code that instantiates a new Button using the Button constructor, a StandardButtonRuntime will be created internally.
Of course, you are not required to create buttons this way - you can also create buttons by adding instances of your component in your Gum screen in the tool, or by instantiating the desired runtime.
ListBoxItems are typically created automatically when items are added to a ListBox instance. We can modify ListBoxItems by creating a runtime object for our ListBoxItem then assigning the ListBox's VisualTemplate.
You may want to rename the class when creating your own version. For example, you may want to name yours CustomListBoxItemRuntime
.
Once you have created your custom ListBoxItem runtime implementation, you can use it on a list box by assigning the VisualTemplate. Be sure to assign it before adding items to your ListBox, as shown in the following code:
Notice that the code above passes a false value to the tryCreateFormsObject
parameter. This prevents the CustomListBoxItemRuntime from creating its own Forms object that would override the default styling.
This page discusses common troubleshooting techniques when your Gum Forms objects are not behaving as expected.
You can check the WindowOver property to see what the Cursor believes it is over. This can tell you if the Cursor is over the object that you expect it to be over. The following code can be used to output the CursorOver to Visual Studio's output window:
Clicks could be offset if the GraphicalUiElement's CanvasWidth and CanvasHeight are set incorrectly. For more information, see the .
You can also output the Cursor's X and Y values to the screen to compare them to the desired object's bounds, as shown in the following code:
Download this file to your game's Content folder, and mark the file as Copy if Newer. Make sure it appears in Visual Studio. For more information on file loading, see the tutorial.
For Buttons, we can add a ButtonCategory state. You are free to implement as many or as few states as you want. For the full list of states see above in the section.
For more information on using a custom runtime defined in your Gum project, see the tutorial.
The easeist way to create a runtime object for ListBoxItem is to copy the existing DefaultListBoxItemRuntime class which can be found here:
Notice that the DefaultListBoxItemRuntime creates visual states beginning on this line: